This cheatsheet provides quick access to common design patterns and their implementations in various programming languages. It’s your go-to reference when you need to solve recurring software design problems.
Installation
Design patterns are a conceptual tool, not a software package. No installation is required.
Core Concepts
Design patterns are general, reusable solutions to commonly occurring problems within a given context in software design. They are not finished designs that can be directly translated into code, but rather descriptions or templates for how to solve a problem that can be used in many different situations.
Key characteristics of design patterns:
- Proven Solutions: They represent best practices that have been refined over time.
- Abstract: They describe a problem and a solution at a higher level than specific code.
- Reusable: They can be applied to different problems and in different contexts.
- Communicative: They provide a common vocabulary for developers to discuss solutions.
Commands / Usage
This section outlines common design patterns and provides illustrative examples. The specific implementation details will vary greatly by programming language.
Creational Patterns
These patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.
Singleton
Ensures a class only has one instance and provides a global point of access to it.
-
Java Example:
public class Singleton { private static Singleton instance; private Singleton() {} // Private constructor public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }Ensures only one instance of
Singletonclass is created. -
Python Example:
class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls) # Initialize other attributes here if needed return cls._instance # Usage s1 = Singleton() s2 = Singleton() print(s1 is s2) # Output: TrueCreates a single instance of the
Singletonclass.
Factory Method
Defines an interface for creating an object, but lets subclasses decide which class to instantiate.
-
Python Example:
class Creator: def factory_method(self): raise NotImplementedError def some_operation(self): product = self.factory_method() return f"Creator: The same creator's code has just worked with {product.operation()}" class ConcreteCreatorA(Creator): def factory_method(self): return ConcreteProductA() class ConcreteCreatorB(Creator): def factory_method(self): return ConcreteProductB() class Product: def operation(self): pass class ConcreteProductA(Product): def operation(self): return "{Result of the ConcreteProductA}" class ConcreteProductB(Product): def operation(self): return "{Result of the ConcreteProductB}" # Usage print("Client: I'm going to use ConcreteCreatorA:") creator_a = ConcreteCreatorA() print(creator_a.some_operation()) print("\nClient: I'm going to use ConcreteCreatorB:") creator_b = ConcreteCreatorB() print(creator_a.some_operation())Allows subclasses to decide which concrete product to create.
Abstract Factory
Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
-
Python Example:
class AbstractFactory: def create_product_a(self): pass def create_product_b(self): pass class ConcreteFactory1(AbstractFactory): def create_product_a(self): return ConcreteProductA1() def create_product_b(self): return ConcreteProductB1() class ConcreteFactory2(AbstractFactory): def create_product_a(self): return ConcreteProductA2() def create_product_b(self): return ConcreteProductB2() class ProductA: pass class ProductB: pass class ConcreteProductA1(ProductA): pass class ConcreteProductB1(ProductB): pass class ConcreteProductA2(ProductA): pass class ConcreteProductB2(ProductB): pass def client_code(factory: AbstractFactory): product_a = factory.create_product_a() product_b = factory.create_product_b() print(f"Created {type(product_a).__name__} and {type(product_b).__name__}") # Usage print("Client: Creating products with ConcreteFactory1:") client_code(ConcreteFactory1()) print("\nClient: Creating products with ConcreteFactory2:") client_code(ConcreteFactory2())Creates families of objects without exposing their concrete classes.
Builder
Separates the construction of a complex object from its representation so that the same construction process can create different representations.
-
Python Example:
class Builder: def reset(self): pass def build_part_a(self): pass def build_part_b(self): pass def build_part_c(self): pass class ConcreteBuilder(Builder): def __init__(self): self.product = Product() def reset(self): self.product = Product() def build_part_a(self): self.product.add("PartA") def build_part_b(self): self.product.add("PartB") def build_part_c(self): self.product.add("PartC") def get_product(self): product = self.product self.reset() # Reset for next build return product class Product: def __init__(self): self.parts = [] def add(self, part): self.parts.append(part) def list_parts(self): print(f"Product parts: {', '.join(self.parts)}") class Director: def __init__(self): self._builder = None def set_builder(self, builder: Builder): self._builder = builder def build_minimal_product(self): self._builder.build_part_a() def build_full_product(self): self._builder.build_part_a() self._builder.build_part_b() self._builder.build_part_c() # Usage builder = ConcreteBuilder() director = Director() director.set_builder(builder) print("Standard basic product:") director.build_minimal_product() builder.get_product().list_parts() print("\nStandard full product:") director.build_full_product() builder.get_product().list_parts() print("\nCustom product:") builder.build_part_a() builder.build_part_c() builder.get_product().list_parts()Builds complex objects step by step, allowing different representations.
Prototype
Specifies the kinds of objects that can be created using a cloned prototype, and creates new objects by copying this prototype.
-
Python Example:
import copy class Prototype: def clone(self): pass class ConcretePrototypeA(Prototype): def __init__(self, value): self.value = value def clone(self): return copy.deepcopy(self) # Deep copy for independent object class ConcretePrototypeB(Prototype): def __init__(self, value, data): self.value = value self.data = data def clone(self): return copy.deepcopy(self) # Usage prototype_a = ConcretePrototypeA("Original A") cloned_a = prototype_a.clone() print(f"Original A: {prototype_a.value}, Cloned A: {cloned_a.value}") cloned_a.value = "Modified A" print(f"Original A after modification: {prototype_a.value}, Cloned A after modification: {cloned_a.value}") prototype_b = ConcretePrototypeB("Original B", [1, 2, 3]) cloned_b = prototype_b.clone() print(f"Original B: {prototype_b.value}, Cloned B: {cloned_b.value}") cloned_b.value = "Modified B" cloned_b.data.append(4) print(f"Original B after modification: {prototype_b.value}, {prototype_b.data}") print(f"Cloned B after modification: {cloned_b.value}, {cloned_b.data}")Creates new objects by copying an existing object (prototype).
Structural Patterns
These patterns are concerned with class and object composition. They explain how to assemble objects into larger structures.
Adapter
Converts the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
-
Python Example:
class Target: def request(self): return "Target: The default target's behavior." class Adaptee: def specific_request(self): return "+Adaptee: The specific request." class Adapter(Target): def __init__(self, adaptee: Adaptee): self._adaptee = adaptee def request(self): return f"Adapter: (TRANSLATED) {self._adaptee.specific_request()}" # Usage adaptee = Adaptee() adapter = Adapter(adaptee) print(adapter.request())Allows objects with incompatible interfaces to collaborate.
Bridge
Decouples an abstraction from its implementation so that the two can vary independently.
-
Python Example:
class Abstraction: def __init__(self, implementor): self._implementor = implementor def operation(self): return self._implementor.operation_impl() class RefinedAbstraction(Abstraction): def operation(self): return f"Refined Abstraction: {self._implementor.operation_impl()} (and more)" class Implementor: def operation_impl(self): pass class ConcreteImplementorA(Implementor): def operation_impl(self): return "Concrete Implementor A" class ConcreteImplementorB(Implementor): def operation_impl(self): return "Concrete Implementor B" # Usage impl_a = ConcreteImplementorA() abstraction_a = Abstraction(impl_a) print(abstraction_a.operation()) impl_b = ConcreteImplementorB() refined_abstraction_b = RefinedAbstraction(impl_b) print(refined_abstraction_b.operation())Separates interface from implementation.
Composite
Composes objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
-
Python Example:
class Component: def __init__(self, name): self.name = name def display(self, indent=""): pass class Leaf(Component): def display(self, indent=""): print(f"{indent}- {self.name} (Leaf)") class Composite(Component): def __init__(self, name): super().__init__(name) self.children = [] def add(self, component): self.children.append(component) def remove(self, component): self.children.remove(component) def display(self, indent=""): print(f"{indent}+ {self.name} (Composite)") for child in self.children: child.display(indent + " ") # Usage root = Composite("Root") branch1 = Composite("Branch 1") leaf1 = Leaf("Leaf 1") leaf2 = Leaf("Leaf 2") branch2 = Composite("Branch 2") leaf3 = Leaf("Leaf 3") branch1.add(leaf1) branch1.add(leaf2) branch2.add(leaf3) root.add(branch1) root.add(branch2) root.display()Treats individual objects and compositions uniformly.
Decorator
Attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
-
Python Example:
class Component: def operation(self): pass class ConcreteComponent(Component): def operation(self): return "ConcreteComponent" class Decorator(Component): def __init__(self, component: Component): self._component = component def operation(self): return self._component.operation() class ConcreteDecoratorA(Decorator): def operation(self): return f"ConcreteDecoratorA({self._component.operation()})" class ConcreteDecoratorB(Decorator): def operation(self): return f"ConcreteDecoratorB({self._component.operation()})" # Usage simple_component = ConcreteComponent() print(f"Client: I've got a simple component:\n{simple_component.operation()}") decorator1 = ConcreteDecoratorA(simple_component) decorator2 = ConcreteDecoratorB(decorator1) print(f"\nClient: Now I've got a decorated component:\n{decorator2.operation()}")Adds responsibilities to objects dynamically without subclassing.
Facade
Provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
-
Python Example:
class SubsystemA: def operation_a(self): return "Subsystem A operation." class SubsystemB: def operation_b(self): return "Subsystem B operation." class Facade: def __init__(self, subsystem_a: SubsystemA, subsystem_b: SubsystemB): self._subsystem_a = subsystem_a self._subsystem_b = subsystem_b def do_something_complex(self): result_a = self._subsystem_a.operation_a() result_b = self._subsystem_b.operation_b() return f"Facade combining: {result_a} and {result_b}" # Usage sub_a = SubsystemA() sub_b = SubsystemB() facade = Facade(sub_a, sub_b) print(facade.do_something_complex())Provides a simplified interface to a complex subsystem.
Flyweight
Uses sharing to support large numbers of fine-grained objects efficiently.
-
Python Example:
class Flyweight: def __init__(self, intrinsic_state): self.intrinsic_state = intrinsic_state def operation(self, extrinsic_state): print(f"Flyweight: {self.intrinsic_state} - Extrinsic: {extrinsic_state}") class FlyweightFactory: def __init__(self): self._flyweights = {} def get_flyweight(self, key): if key not in self._flyweights: self._flyweights[key] = Flyweight(key) return self._flyweights[key] # Usage factory = FlyweightFactory() flyweight1 = factory.get_flyweight("shared_state_1") flyweight1.operation("extrinsic_state_A") flyweight2 = factory.get_flyweight("shared_state_2") flyweight2.operation("extrinsic_state_B") # Demonstrating sharing flyweight3 = factory.get_flyweight("shared_state_1") flyweight3.operation("extrinsic_state_C") print(f"flyweight1 is flyweight3: {flyweight1 is flyweight3}")Manages a pool of shared objects to reduce memory usage.
Proxy
A surrogate or placeholder for another object to control access to it.
-
Python Example:
class Subject: def request(self): pass class RealSubject(Subject): def request(self): return "RealSubject: Handling request." class Proxy(Subject): def __init__(self, real_subject: RealSubject): self._real_subject = real_subject def request(self): if self._check_access(): return self._real_subject.request() else: return "Proxy: Access denied." def _check_access(self): print("Proxy: Checking access...") return True # Simulate access check # Usage real_subject = RealSubject() proxy = Proxy(real_subject) print(proxy.request())Provides a surrogate or placeholder for another object.
Behavioral Patterns
These patterns are concerned with algorithms and the assignment of responsibilities between objects.
Chain of Responsibility
Avoids coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chains the receiving objects and passes the request along the chain until an object handles it.
-
Python Example:
class Handler: def __init__(self): self.next_handler = None def set_next(self, handler): self.next_handler = handler return handler def handle(self, request): if self.next_handler: return self.next_handler.handle(request) return None class ConcreteHandlerA(Handler): def handle(self, request): if "A" in request: return f"ConcreteHandlerA handled: {request}" else: return super().handle(request) class ConcreteHandlerB(Handler): def handle(self, request): if "B" in request: return f"ConcreteHandlerB handled: {request}" else: return super().handle(request) # Usage handler_a = ConcreteHandlerA() handler_b = ConcreteHandlerB() handler_a.set_next(handler_b) print("Handling request 'Request A':", handler_a.handle("Request A")) print("Handling request 'Request B':", handler_a.handle("Request B")) print("Handling request 'Request C':", handler_a.handle("Request C"))Passes requests along a chain of handlers.
Command
Encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
-
Python Example:
class Command: def execute(self): pass class Receiver: def action(self): return "Receiver action." class ConcreteCommand(Command): def __init__(self, receiver: Receiver): self._receiver = receiver def execute(self): return f"ConcreteCommand executing: {self._receiver.action()}" class Invoker: def __init__(self): self._command = None def set_command(self, command: Command): self._command = command def run_command(self): if self._command: return self._command.execute() return "No command set." # Usage receiver = Receiver() command = ConcreteCommand(receiver) invoker = Invoker() invoker.set_command(command) print(invoker.run_command())Encapsulates a request as an object.
Interpreter
Given a language, defines a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
-
Python Example (Simplified):
class Expression: def interpret(self): pass class TerminalExpression(Expression): def __init__(self, name): self.name = name def interpret(self): return self.name class NonTerminalExpression(Expression): def __init__(self, expression1: Expression, expression2: Expression): self._expression1 = expression1 self._expression2 = expression2 def interpret(self): return f"({self._expression1.interpret()} + {self._expression2.interpret()})" # Usage (representing a simple grammar like (A + B)) expr1 = TerminalExpression("A") expr2 = TerminalExpression("B") non_terminal = NonTerminalExpression(expr1, expr2) print(non_terminal.interpret())Defines a representation for a grammar and an interpreter for that grammar.
Iterator
Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
-
Python Example:
class Iterator: def __init__(self, collection): self._collection = collection self._index = 0 def __iter__(self): return self def __next__(self): if self._index < len(self._collection): item = self._collection[self._index] self._index += 1 return item else: raise StopIteration class Collection: def __init__(self, items): self._items = items def __iter__(self): return Iterator(self._items) # Usage my_collection = Collection(["apple", "banana", "cherry"]) for item in my_collection: print(item)Provides sequential access to elements of a collection.
Mediator
Defines an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
-
Python Example:
class Mediator: def notify(self, sender, event): pass class Colleague: def __init__(self, mediator: Mediator): self._mediator = mediator def send(self, event): self._mediator.notify(self, event) class ConcreteColleagueA(Colleague): def receive(self, event): print(f"ConcreteColleagueA received event: {event}") class ConcreteColleagueB(Colleague): def receive(self, event): print(f"ConcreteColleagueB received event: {event}") class ConcreteMediator(Mediator): def __init__(self): self.colleague_a = None self.colleague_b = None def set_colleague_a(self, colleague_a: ConcreteColleagueA): self.colleague_a = colleague_a def set_colleague_b(self, colleague_b: ConcreteColleagueB): self.colleague_b = colleague_b def notify(self, sender, event): if sender is self.colleague_a: self.colleague_b.receive(f"Mediated event from A: {event}") elif sender is self.colleague_b: self.colleague_a.receive(f"Mediated event from B: {event}") # Usage mediator = ConcreteMediator() colleague_a = ConcreteColleagueA(mediator) colleague_b = ConcreteColleagueB(mediator) mediator.set_colleague_a(colleague_a) mediator.set_colleague_b(colleague_b) colleague_a.send("Hello from A") colleague_b.send("Hi from B")Mediates interactions between objects.
Memento
Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.
-
Python Example:
class Memento: def __init__(self, state): self._state = state def get_state(self): return self._state class Originator: def __init__(self): self._state = None def set_state(self, state): self._state = state print(f"Originator: Setting state to {self._state}") def save_to_memento(self): print("Originator: Saving to Memento.") return Memento(self._state) def restore_from_memento(self, memento: Memento): self._state = memento.get_state() print(f"Originator: Restored from Memento. State is {self._state}") class Caretaker: def __init__(self): self._memento = None def save(self, originator: Originator): print("Caretaker: Saving Originator's state.") self._memento = originator.save_to_memento() def restore(self, originator: Originator): print("Caretaker: Restoring Originator's state.") if self._memento: originator.restore_from_memento(self._memento) # Usage originator = Originator() caretaker = Caretaker() originator.set_state("State #1") caretaker.save(originator) originator.set_state("State #2") # Change state originator.set_state("State #3") caretaker.restore(originator)Captures and restores an object’s internal state.
Observer
Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
-
Python Example:
class Subject: def __init__(self): self._observers = [] def attach(self, observer): self._observers.append(observer) def detach(self, observer): self._observers.remove(observer) def notify(self, event): for observer in self._observers: observer.update(self, event) class ConcreteSubject(Subject): def do_something(self): print("ConcreteSubject: Doing something and notifying observers.") self.notify("Something happened") class Observer: def update(self, subject, event): pass class ConcreteObserverA(Observer): def update(self, subject, event): print(f"ConcreteObserverA received update: {event} from {type(subject).__name__}") class ConcreteObserverB(Observer): def update(self, subject, event): print(f"ConcreteObserverB received update: {event} from {type(subject).__name__}") # Usage subject = ConcreteSubject() observer_a = ConcreteObserverA() observer_b = ConcreteObserverB() subject.attach(observer_a) subject.attach(observer_b) subject.do_something() subject.detach(observer_a) subject.do_something()Defines a publish-subscribe mechanism.
State
Allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
-
Python Example:
class State: def handle(self): pass class ConcreteStateA(State): def handle(self): return "ConcreteStateA handling." class ConcreteStateB(State): def handle(self): return "ConcreteStateB handling." class Context: def __init__(self): self._state = None def set_state(self, state: State): self._state = state print(f"Context: State changed to {type(self._state).__name__}") def request(self): return f"Context: {self._state.handle()}" # Usage context = Context() state_a = ConcreteStateA() state_b = ConcreteStateB() context.set_state(state_a) print(context.request()) context.set_state(state_b) print(context.request())Allows an object to change its behavior based on its internal state.
Strategy
Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
-
Python Example:
class Strategy: def execute(self, data): pass class ConcreteStrategyA(Strategy): def execute(self, data): return f"ConcreteStrategyA: {data} processed." class ConcreteStrategyB(Strategy): def execute(self, data): return f"ConcreteStrategyB: {data} processed." class Context: def __init__(self, strategy: Strategy): self._strategy = strategy def set_strategy(self, strategy: Strategy): self._strategy = strategy def execute_strategy(self, data): return self._strategy.execute(data) # Usage strategy_a = ConcreteStrategyA() context = Context(strategy_a) print(context.execute_strategy("some data")) strategy_b = ConcreteStrategyB() context.set_strategy(strategy_b) print(context.execute_strategy("other data"))Defines a family of algorithms and makes them interchangeable.
Template Method
Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
-
Python Example:
class AbstractClass: def template_method(self): self.step1() self.step2() self.step3() def step1(self): raise NotImplementedError def step2(self): pass # Optional step def step3(self): raise NotImplementedError class ConcreteClassA(AbstractClass): def step1(self): print("ConcreteClassA: Step 1") def step3(self): print("ConcreteClassA: Step 3") class ConcreteClassB(AbstractClass): def step1(self): print("ConcreteClassB: Step 1") def step2(self): print("ConcreteClassB: Step 2 (overridden)") def step3(self): print("ConcreteClassB: Step 3") # Usage print("Running ConcreteClassA:") concrete_a = ConcreteClassA() concrete_a.template_method() print("\nRunning ConcreteClassB:") concrete_b = ConcreteClassB() concrete_b.template_method()Defines the skeleton of an algorithm, allowing subclasses to fill in specific steps.
Visitor
Represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
-
Python Example:
class Visitor: def visit_concrete_element_a(self, element): pass def visit_concrete_element_b(self, element): pass class ConcreteVisitor1(Visitor): def visit_concrete_element_a(self, element): print(f"{element.operation_a()} + ConcreteVisitor1") def visit_concrete_element_b(self, element): print(f"{element.operation_b()} + ConcreteVisitor1") class ConcreteVisitor2(Visitor): def visit_concrete_element_a(self, element): print(f"{element.operation_a()} + ConcreteVisitor2") def visit_concrete_element_b(self, element): print(f"{element.operation_b()} + ConcreteVisitor2") class Element: def accept(self, visitor: Visitor): pass class ConcreteElementA(Element): def operation_a(self): return "ConcreteElementA's operation" def accept(self, visitor: Visitor): visitor.visit_concrete_element_a(self) class ConcreteElementB(Element): def operation_b(self): return "ConcreteElementB's operation" def accept(self, visitor: Visitor): visitor.visit_concrete_element_b(self) # Usage elements = [ConcreteElementA(), ConcreteElementB()] visitor1 = ConcreteVisitor1() visitor2 = ConcreteVisitor2() print("Visiting elements with Visitor1:") for element in elements: element.accept(visitor1) print("\nVisiting elements with Visitor2:") for element in elements: element.accept(visitor2)Defines new operations for an object structure without altering the structure itself.
Common Patterns
These are not specific design patterns but rather common ways design patterns are used in conjunction with other tools or techniques.
-
Dependency Injection with Factories: Using a Factory pattern to create objects that are then injected into other objects. This decouples the creation of dependencies.
# Conceptual Example class Service: def perform_task(self): print("Performing service task.") class ServiceFactory: def create_service(self): return Service() class Client: def __init__(self, service_factory: ServiceFactory): self.service = service_factory.create_service() def do_work(self): self.service.perform_task() # Usage factory = ServiceFactory() client = Client(factory) client.do_work() -
State Pattern for Finite State Machines: Implementing a finite state machine using the State pattern, where each state is a concrete class.
# Conceptual Example class State: def handle_input(self, context): pass class StateA(State): def handle_input(self, context): print("Transitioning from A to B") context.set_state(StateB()) class StateB(State): def handle_input(self, context): print("Transitioning from