Overview

14 The Singleton, Composite, and Decorator Design Patterns

This chapter presents three design patterns that help Python applications manage object creation, structure, and runtime responsibilities to keep code simple, flexible, and uniform to use. The patterns address common architectural needs: constraining a system to a single shared resource, treating individual objects and collections the same way, and adding features to objects on the fly without changing their code. Through before-and-after refactorings, the chapter shows how adopting these patterns reduces coupling, clarifies responsibilities, and improves extensibility, while cautioning not to confuse the Decorator pattern with Python’s syntactic “@decorators.”

The Singleton pattern guarantees only one instance of a class exists and provides a single, global point of access to it. A naive global-variable approach fails because it permits copies, multiple instances, undefined creation order, and unnecessary lifetime. The refactored solution centralizes access in a class method that lazily creates the instance, stores it in a private class variable, and allows deletion to enable recreation later. It blocks direct construction and copying by overriding __new__, __copy__, and __deepcopy__, ensuring DF1–DF6 (access, sameness, lazy creation, non-existence until needed, uniqueness, and recreatability). The chapter also flags race conditions in multithreaded contexts if instance creation isn’t protected.

The Composite pattern structures data as part-whole trees so clients treat leaves and composites uniformly. By making the composite class a subclass of the same base as leaves, common operations (like cost computation and printing) become recursive and independent of whether a node is a leaf or a group, yielding uniformity, simplicity, encapsulation, and flexibility. The Decorator pattern adds responsibilities dynamically by wrapping objects with decorator instances that share the same interface as the wrapped component. Each decorator holds a link to the next object and contributes its own behavior (for example, a ticket’s extra cost), enabling any number, order, and combination of features at run time without changing the base class or client code, and keeping enhancements cohesive and loosely coupled.

An unsuccessful attempt at a singleton class.
A well-designed singleton object. The private class variable _instance is a reference to the singleton object if it exists, or None otherwise. The public class method obtain() returns a reference to the singleton object. It first creates the singleton if it doesn’t already exist.
The generic model of the Singleton Design Pattern. Compare with figure 14.2. The private static instance variable singleton refers to the Singleton object if it exists; otherwise, its value is null. The private static method get_singleton() returns a reference to the existing Singleton object. If the singleton object doesn’t already exist, the function creates and returns the reference to a newly created Singleton object.
The hierarchy of objects in a tree data structure that represent the provisions for a baseball player and the cost of each item. The composite objects are shaded gray.
Classes Ball, Bat, Glove, Cap, Jersey, Pants, Socks, Shoes, and Sunscreen are subclasses of class ProvisionItem. Composite classes EquipmentGroup, UniformGroup, and FootwearGroup are subclasses of ProvisionGroup, and each has a list of ProvisionItem objects.
In the second version of our cost report application modeled by the Composite Design Pattern, class ProvisionGroup is now itself a subclass of class ProvisionItem. UniformGroup now aggegates FootwearGroup. The grayed-out portions of the diagram haven’t changed logically from figure 14.5.
The generic model of the Composite Design Pattern. Compare with figure 14.6. Both the individual Leaf class and the Composite class inherit from the Component superclass.
We implement the enhancements to a base ticket as instance variables of the Ticket class. Each enhancement has a cost.
An enhanced ticket is conceptually wrapped by any number of pregame party, VIP seating, and drink coupon enhancement decorators. Each decorator wraps the base ticket and any prior wrappers. To calculate the cost of an enhanced ticket, each decorator calls the cost() method of whatever it wraps (either another decorator or the base ticket). Each return value is the cost of the decorator plus the total cost of whatever it wraps.
Each decorator object except the last on in the chain points to the enhancement object that it wraps. The last enhancement object in the chain points to the base ticket object.
Abstract superclass Ticket has subclasses that represent either a base ticket or a ticket wrapped with enhancements. The Enhancement superclass has a protected link to the next Enhancement object or to the BaseTicket object. Party, VIP, and Coupon are enhancements. One or more of their objects can wrap a BaseTicket object. Each Enhancement object adds the responsibility to include its cost to the total ticket cost.
The generic model of the Decorator Design Pattern. Compare with figure 14.11. A ConcreteComponent object by itself is a Component. A ConcreteComponent wrapped by Decorator objects is also a Component. The private component instance variable of superclass Decorator is either a ConcreteComponent object or to a Decorator object. This chain implements the nested wrapping of the Decorator objects.

Summary

  • The Singleton Design Pattern models code that must ensure that at most one object of a given class can exist during the run time of an application. We must control the creation of the object to ensure that there can be at most one instance of the singleton. A static instance variable points to the singleton object at run time.
  • The Singleton Design Pattern also requires overriding the singleton class’s built-in __copy__() and __deepcopy__() methods. This prevents making copies of the singleton object during run time. We must be cautious that a multithreaded application does not create multiple singleton objects.
  • The Composite Design Pattern models code that works with hierarchical tree-structured data.
  • The Composite Design Pattern simplifies the code by providing the same interface for classes that represent individual objects as for classes that represent composite objects. That allows our code to treat individual and composite objects uniformly.
  • The Decorator Design Pattern models code that allows us to extend the responsibilities of an object at run time. This is accomplished with decorations in the form of attributes and behaviors that we can implement as wrapper objects.
  • The Decorator Design Pattern lessens the need to hardcode additional responsibilities for an object by making it easy to add new decorations or modify or remove existing ones without modifying any other classes.

FAQ

What common theme links the Singleton, Composite, and Decorator patterns in this chapter?All three patterns help you manage one or more objects so they behave as a unified whole, simplifying client code and increasing flexibility. Singleton models a collection of exactly one object with a global access point; Composite models trees so clients can treat leaves and groups uniformly; Decorator lets you add responsibilities to an object dynamically without changing its class.
What are the essential design features of a well-implemented Singleton?- A global access point to the single instance (for example, a class method like obtain()).
- Calls always return the same instance.
- Lazy creation: create the instance on first access only.
- Do not create the instance if it is never used.
- Prevent multiple instances from ever existing.
- Allow deleting the instance so a new one can be created later (for example, a delete() class method).
Why isn’t a global variable a safe way to implement a Singleton?- Anyone can replace or mutate the global unexpectedly.
- Initialization order across modules is undefined, causing subtle bugs.
- The object always exists (no lazy creation), even if never used.
- It can be copied or a second instance can be created, breaking the “only one instance” rule.
How does the chapter implement a Singleton in Python?It uses a private class variable (for example, _instance) to hold the sole object; a public class method (for example, obtain(holder)) that lazily creates the instance via super().__new__(cls) if needed and returns it; a delete() class method that clears _instance; and guards that block direct construction and copying by raising in __new__, __copy__, and __deepcopy__.
What extra care is needed for Singletons in multithreaded programs?Concurrent calls that observe _instance is None can create more than one instance (a race condition). Protect lazy initialization with appropriate synchronization (for example, a lock) to ensure exactly one instance is created.
What problem does the Composite pattern solve?It lets clients treat individual objects and compositions uniformly in a part–whole tree. Operations like computing totals or printing can recurse over the tree without special-case logic, and you can add parts or groups at runtime.
How did using Composite simplify the cost report example?By making ProvisionGroup a subclass of ProvisionItem, both leaves and groups share the same interface (cost, print_item(), etc.). The report generator only needs the tree root and calls print_item(); groups sum or print their children recursively, so the code became shorter, more flexible, and decoupled from the tree’s shape.
What is the Decorator pattern and how is it different from Python’s language decorators?The Decorator design pattern wraps an object with “decorations” that add responsibilities at runtime while preserving the object’s interface. In the chapter, each enhancement is a Ticket subclass that holds a reference to another Ticket and adds its own cost. This is unrelated to Python’s @decorator syntax for functions/methods/classes; don’t confuse the two.
How do decorators compose in the enhanced ticket example?Start with a BaseTicket, then wrap it with any number of enhancement objects (for example, Party, VIP, Coupon) in any order. Each decorator stores the wrapped Ticket and its cost returns “my price + wrapped.cost”. Multiple coupons are modeled by wrapping repeatedly with Coupon.
When should I prefer Decorator over subclassing or feature flags?Use Decorator when you need to add, remove, or combine features flexibly at runtime without modifying the base class or creating a subclass explosion. It keeps classes cohesive and loosely coupled, avoids hardcoded combinations, and lets clients treat base and decorated objects uniformly.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Software Design for Python Programmers ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Software Design for Python Programmers ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Software Design for Python Programmers ebook for free