Last updated: 2026-09-23
Design Patterns
Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem." — Christopher Alexander1
The quote above is doing real work, not just decorating the page: Alexander wasn't writing about software at all — his "pattern language" catalogued recurring solutions in architecture and urban planning, for towns, buildings, and rooms. Gamma, Helm, Johnson, and Vlissides (the "Gang of Four," GoF) borrowed the idea directly, adapting it into the catalogue of 23 software design patterns this page draws from, organised into the same three categories used below — creational, structural, and behavioural2. Every pattern on this page is one of theirs, in their original grouping; the code across five languages is this site's, but the patterns and their names are not this site's invention.
Creational Patterns
Singleton
Ensure a class has only one instance, provide global access.
class Singleton:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, '_initialized'):
self._initialized = True
# initialization here
#include <mutex>
#include <memory>
class Singleton {
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton& getInstance() {
static std::unique_ptr<Singleton> instance;
static std::once_flag flag;
std::call_once(flag, []{ instance = std::make_unique<Singleton>(); });
return *instance;
}
};
public final class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
public sealed class Singleton {
private static readonly Lazy<Singleton> _instance =
new Lazy<Singleton>(() => new Singleton());
private Singleton() {}
public static Singleton Instance => _instance.Value;
}
require "singleton"
class AppConfig
include Singleton # thread-safe lazy instantiation built in
def initialize
# initialisation here
end
end
# Usage
config = AppConfig.instance
config.equal?(AppConfig.instance) # => true (same object)
Factory Method
Define interface for creating objects, let subclasses decide which class to instantiate.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self) -> str:
pass
class Dog(Animal):
def speak(self) -> str:
return "Woof!"
class Cat(Animal):
def speak(self) -> str:
return "Meow!"
class AnimalFactory(ABC):
@abstractmethod
def create(self) -> Animal:
pass
class DogFactory(AnimalFactory):
def create(self) -> Animal:
return Dog()
class CatFactory(AnimalFactory):
def create(self) -> Animal:
return Cat()
#include <memory>
#include <iostream>
class Animal {
public:
virtual ~Animal() = default;
virtual void speak() const = 0;
};
class Dog : public Animal {
public:
void speak() const override { std::cout << "Woof!\n"; }
};
class Cat : public Animal {
public:
void speak() const override { std::cout << "Meow!\n"; }
};
class AnimalFactory {
public:
virtual ~AnimalFactory() = default;
virtual std::unique_ptr<Animal> create() = 0;
};
class DogFactory : public AnimalFactory {
public:
std::unique_ptr<Animal> create() override { return std::make_unique<Dog>(); }
};
class CatFactory : public AnimalFactory {
public:
std::unique_ptr<Animal> create() override { return std::make_unique<Cat>(); }
};
interface Animal {
void speak();
}
final class Dog implements Animal {
@Override public void speak() { System.out.println("Woof!"); }
}
final class Cat implements Animal {
@Override public void speak() { System.out.println("Meow!"); }
}
interface AnimalFactory {
Animal create();
}
final class DogFactory implements AnimalFactory {
@Override public Animal create() { return new Dog(); }
}
final class CatFactory implements AnimalFactory {
@Override public Animal create() { return new Cat(); }
}
public interface IAnimal {
void Speak();
}
public sealed class Dog : IAnimal {
public void Speak() => Console.WriteLine("Woof!");
}
public sealed class Cat : IAnimal {
public void Speak() => Console.WriteLine("Meow!");
}
public interface IAnimalFactory {
IAnimal Create();
}
public sealed class DogFactory : IAnimalFactory {
public IAnimal Create() => new Dog();
}
public sealed class CatFactory : IAnimalFactory {
public IAnimal Create() => new Cat();
}
class Dog
def speak
"Woof!"
end
end
class Cat
def speak
"Meow!"
end
end
class AnimalFactory
def create = raise NotImplementedError
end
class DogFactory < AnimalFactory
def create
Dog.new
end
end
class CatFactory < AnimalFactory
def create
Cat.new
end
end
Abstract Factory
Provide interface for creating families of related objects.
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def render(self) -> str: pass
class Checkbox(ABC):
@abstractmethod
def render(self) -> str: pass
class WinButton(Button):
def render(self) -> str: return "[Windows Button]"
class MacButton(Button):
def render(self) -> str: return "[Mac Button]"
class WinCheckbox(Checkbox):
def render(self) -> str: return "[Windows Checkbox]"
class MacCheckbox(Checkbox):
def render(self) -> str: return "[Mac Checkbox]"
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button: pass
@abstractmethod
def create_checkbox(self) -> Checkbox: pass
class WinFactory(GUIFactory):
def create_button(self) -> Button: return WinButton()
def create_checkbox(self) -> Checkbox: return WinCheckbox()
class MacFactory(GUIFactory):
def create_button(self) -> Button: return MacButton()
def create_checkbox(self) -> Checkbox: return MacCheckbox()
class Button { public: virtual ~Button() = default; virtual void render() = 0; };
class Checkbox { public: virtual ~Checkbox() = default; virtual void render() = 0; };
class WinButton : public Button { void render() override { std::cout << "[Windows Button]\n"; } };
class MacButton : public Button { void render() override { std::cout << "[Mac Button]\n"; } };
class WinCheckbox : public Checkbox { void render() override { std::cout << "[Windows Checkbox]\n"; } };
class MacCheckbox : public Checkbox { void render() override { std::cout << "[Mac Checkbox]\n"; } };
class GUIFactory {
public:
virtual ~GUIFactory() = default;
virtual std::unique_ptr<Button> createButton() = 0;
virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
};
class WinFactory : public GUIFactory {
public:
std::unique_ptr<Button> createButton() override { return std::make_unique<WinButton>(); }
std::unique_ptr<Checkbox> createCheckbox() override { return std::make_unique<WinCheckbox>(); }
};
class MacFactory : public GUIFactory {
public:
std::unique_ptr<Button> createButton() override { return std::make_unique<MacButton>(); }
std::unique_ptr<Checkbox> createCheckbox() override { return std::make_unique<MacCheckbox>(); }
};
interface Button { void render(); }
interface Checkbox { void render(); }
final class WinButton implements Button { public void render() { System.out.println("[Windows Button]"); } }
final class MacButton implements Button { public void render() { System.out.println("[Mac Button]"); } }
final class WinCheckbox implements Checkbox { public void render() { System.out.println("[Windows Checkbox]"); } }
final class MacCheckbox implements Checkbox { public void render() { System.out.println("[Mac Checkbox]"); } }
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
final class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
final class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
}
public interface IButton { void Render(); }
public interface ICheckbox { void Render(); }
public sealed class WinButton : IButton { public void Render() => Console.WriteLine("[Windows Button]"); }
public sealed class MacButton : IButton { public void Render() => Console.WriteLine("[Mac Button]"); }
public sealed class WinCheckbox : ICheckbox { public void Render() => Console.WriteLine("[Windows Checkbox]"); }
public sealed class MacCheckbox : ICheckbox { public void Render() => Console.WriteLine("[Mac Checkbox]"); }
public interface IGUIFactory {
IButton CreateButton();
ICheckbox CreateCheckbox();
}
public sealed class WinFactory : IGUIFactory {
public IButton CreateButton() => new WinButton();
public ICheckbox CreateCheckbox() => new WinCheckbox();
}
class WinButton
def render = "[Windows Button]"
end
class MacButton
def render = "[Mac Button]"
end
class WinCheckbox
def render = "[Windows Checkbox]"
end
class MacCheckbox
def render = "[Mac Checkbox]"
end
class WinFactory
def create_button = WinButton.new
def create_checkbox = WinCheckbox.new
end
class MacFactory
def create_button = MacButton.new
def create_checkbox = MacCheckbox.new
end
Builder
Separate construction from representation.
class Computer:
def __init__(self, cpu: str, ram: str, storage: str, gpu: str = ""):
self.cpu = cpu
self.ram = ram
self.storage = storage
self.gpu = gpu
def __str__(self) -> str:
return f"Computer({self.cpu}, {self.ram}, {self.storage}, {self.gpu})"
class ComputerBuilder:
def __init__(self):
self._cpu = ""
self._ram = ""
self._storage = ""
self._gpu = ""
def cpu(self, val: str) -> 'ComputerBuilder':
self._cpu = val
return self
def ram(self, val: str) -> 'ComputerBuilder':
self._ram = val
return self
def storage(self, val: str) -> 'ComputerBuilder':
self._storage = val
return self
def gpu(self, val: str) -> 'ComputerBuilder':
self._gpu = val
return self
def build(self) -> 'Computer':
return Computer(self._cpu, self._ram, self._storage, self._gpu)
# Usage
pc = ComputerBuilder().cpu("Intel i9").ram("32GB").storage("1TB SSD").gpu("RTX 4090").build()
#include <string>
class Computer {
std::string cpu_, ram_, storage_, gpu_;
Computer(std::string cpu, std::string ram, std::string storage, std::string gpu)
: cpu_(cpu), ram_(ram), storage_(storage), gpu_(gpu) {}
friend class Builder;
public:
class Builder {
std::string cpu_, ram_, storage_, gpu_;
public:
Builder& cpu(std::string v) { cpu_ = std::move(v); return *this; }
Builder& ram(std::string v) { ram_ = std::move(v); return *this; }
Builder& storage(std::string v) { storage_ = std::move(v); return *this; }
Builder& gpu(std::string v) { gpu_ = std::move(v); return *this; }
Computer build() { return Computer(cpu_, ram_, storage_, gpu_); }
};
};
public final class Computer {
private final String cpu, ram, storage, gpu;
private Computer(Builder b) { this.cpu = b.cpu; this.ram = b.ram; this.storage = b.storage; this.gpu = b.gpu; }
public static class Builder {
private String cpu = "", ram = "", storage = "", gpu = "";
public Builder cpu(String v) { this.cpu = v; return this; }
public Builder ram(String v) { this.ram = v; return this; }
public Builder storage(String v) { this.storage = v; return this; }
public Builder gpu(String v) { this.gpu = v; return this; }
public Computer build() { return new Computer(this); }
}
}
public sealed class Computer {
public string Cpu { get; }
public string Ram { get; }
public string Storage { get; }
public string Gpu { get; }
private Computer(Builder b) {
Cpu = b.Cpu; Ram = b.Ram; Storage = b.Storage; Gpu = b.Gpu;
}
public sealed class Builder {
public string Cpu { get; set; } = "";
public string Ram { get; set; } = "";
public string Storage { get; set; } = "";
public string Gpu { get; set; } = "";
public Computer Build() => new Computer(this);
}
}
// Usage
var pc = new Computer.Builder()
.Cpu("Intel i9").Ram("32GB").Storage("1TB SSD").Gpu("RTX 4090")
.Build();
Computer = Struct.new(:cpu, :ram, :storage, :gpu) do
def to_s
"Computer(#{cpu}, #{ram}, #{storage}, #{gpu})"
end
end
class ComputerBuilder
def initialize
@cpu = @ram = @storage = @gpu = ""
end
def cpu(val)
@cpu = val
self
end
def ram(val)
@ram = val
self
end
def storage(val)
@storage = val
self
end
def gpu(val)
@gpu = val
self
end
def build
Computer.new(@cpu, @ram, @storage, @gpu)
end
end
# Usage
pc = ComputerBuilder.new.cpu("Intel i9").ram("32GB").storage("1TB SSD").gpu("RTX 4090").build
Structural Patterns
Adapter
Convert interface of class into another interface client expects.
from abc import ABC, abstractmethod
from typing import Dict
class LegacyXMLParser:
def parse_xml(self, xml: str) -> Dict[str, str]:
return {"data": "parsed from XML"}
class JSONParser(ABC):
@abstractmethod
def parse(self, json: str) -> Dict[str, str]: pass
class XMLToJSONAdapter(JSONParser):
def __init__(self, parser: 'LegacyXMLParser'):
self.parser = parser
def parse(self, json: str) -> Dict[str, str]:
xml = self.json_to_xml(json)
return self.parser.parse_xml(xml)
def json_to_xml(self, json: str) -> str:
# conversion logic
return "<xml>converted</xml>"
#include <map>
#include <string>
#include <memory>
class LegacyXMLParser {
public:
std::map<std::string, std::string> parseXML(const std::string& xml) {
return {{"data", "parsed from XML"}};
}
};
class JSONParser {
public:
virtual std::map<std::string, std::string> parse(const std::string& json) = 0;
virtual ~JSONParser() = default;
};
class XMLToJSONAdapter : public JSONParser {
std::unique_ptr<LegacyXMLParser> parser_;
public:
explicit XMLToJSONAdapter(std::unique_ptr<LegacyXMLParser> p) : parser_(std::move(p)) {}
std::map<std::string, std::string> parse(const std::string& json) override {
std::string xml = jsonToXML(json);
return parser_->parseXML(xml);
}
std::string jsonToXML(const std::string& json) { return "<xml>converted</xml>"; }
};
import java.util.*;
class LegacyXMLParser {
public Map<String, String> parseXML(String xml) {
return Map.of("data", "parsed from XML");
}
}
interface JSONParser {
Map<String, String> parse(String json);
}
class XMLToJSONAdapter implements JSONParser {
private final LegacyXMLParser parser;
public XMLToJSONAdapter(LegacyXMLParser p) { parser = p; }
public Map<String, String> parse(String json) {
String xml = jsonToXML(json);
return parser.parseXML(xml);
}
String jsonToXML(String json) { return "<xml>converted</xml>"; }
}
using System.Collections.Generic;
public class LegacyXMLParser {
public Dictionary<string, string> ParseXML(string xml) {
return new Dictionary<string, string> { {"data", "parsed from XML"} };
}
}
public interface IJSONParser {
Dictionary<string, string> Parse(string json);
}
public class XMLToJSONAdapter : IJSONParser {
private readonly LegacyXMLParser _parser;
public XMLToJSONAdapter(LegacyXMLParser p) => _parser = p;
public Dictionary<string, string> Parse(string json) {
string xml = JsonToXml(json);
return _parser.ParseXML(xml);
}
string JsonToXml(string json) => "<xml>converted</xml>";
}
class LegacyXMLParser
def parse_xml(_xml)
{ "data" => "parsed from XML" }
end
end
class XMLToJSONAdapter
def initialize(parser)
@parser = parser
end
def parse(json)
xml = json_to_xml(json)
@parser.parse_xml(xml)
end
private
def json_to_xml(_json)
# conversion logic
"<xml>converted</xml>"
end
end
Structural Patterns (continued)
Decorator
Attach additional responsibilities dynamically.
from abc import ABC, abstractmethod
class Coffee(ABC):
@abstractmethod
def cost(self) -> float: pass
@abstractmethod
def description(self) -> str: pass
class SimpleCoffee(Coffee):
def cost(self) -> float: return 2.0
def description(self) -> str: return "Simple coffee"
class CoffeeDecorator(Coffee):
def __init__(self, coffee: Coffee):
self._coffee = coffee
def cost(self) -> float:
return self._coffee.cost()
def description(self) -> str:
return self._coffee.description()
class MilkDecorator(CoffeeDecorator):
def cost(self) -> float:
return self._coffee.cost() + 0.5
def description(self) -> str:
return self._coffee.description() + ", Milk"
class SugarDecorator(CoffeeDecorator):
def cost(self) -> float:
return self._coffee.cost() + 0.2
def description(self) -> str:
return self._coffee.description() + ", Sugar"
# Usage
coffee = SimpleCoffee()
coffee = MilkDecorator(coffee)
coffee = SugarDecorator(coffee)
print(f"{coffee.description()} = ${coffee.cost()}")
#include <string>
#include <memory>
#include <iostream>
class Coffee {
public:
virtual ~Coffee() = default;
virtual double cost() const = 0;
virtual std::string description() const = 0;
};
class SimpleCoffee : public Coffee {
double cost() const override { return 2.0; }
std::string description() const override { return "Simple coffee"; }
};
class CoffeeDecorator : public Coffee {
std::unique_ptr<Coffee> coffee_;
public:
explicit CoffeeDecorator(std::unique_ptr<Coffee> c) : coffee_(std::move(c)) {}
double cost() const override { return coffee_->cost(); }
std::string description() const override { return coffee_->description(); }
};
class MilkDecorator : public CoffeeDecorator {
public:
explicit MilkDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
double cost() const override { return coffee_->cost() + 0.5; }
std::string description() const override { return coffee_->description() + ", Milk"; }
};
class SugarDecorator : public CoffeeDecorator {
public:
explicit SugarDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
double cost() const override { return coffee_->cost() + 0.2; }
std::string description() const override { return coffee_->description() + ", Sugar"; }
};
interface Coffee {
double cost();
String description();
}
class SimpleCoffee implements Coffee {
public double cost() { return 2.0; }
public String description() { return "Simple coffee"; }
}
abstract class CoffeeDecorator implements Coffee {
protected final Coffee coffee;
CoffeeDecorator(Coffee c) { this.coffee = c; }
public double cost() { return coffee.cost(); }
public String description() { return coffee.description(); }
}
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee c) { super(c); }
public double cost() { return coffee.cost() + 0.5; }
public String description() { return coffee.description() + ", Milk"; }
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee c) { super(c); }
public double cost() { return coffee.cost() + 0.2; }
public String description() { return coffee.description() + ", Sugar"; }
}
using System;
public interface ICoffee {
double Cost { get; }
string Description { get; }
}
public sealed class SimpleCoffee : ICoffee {
public double Cost { get; } = 2.0;
public string Description { get; } = "Simple coffee";
}
public abstract class CoffeeDecorator : ICoffee {
protected readonly ICoffee Coffee;
protected CoffeeDecorator(ICoffee c) => Coffee = c;
public virtual double Cost => Coffee.Cost;
public virtual string Description => Coffee.Description;
}
public sealed class MilkDecorator : CoffeeDecorator {
public MilkDecorator(ICoffee c) : base(c) {}
public override double Cost => Coffee.Cost + 0.5;
public override string Description => Coffee.Description + ", Milk";
}
public sealed class SugarDecorator : CoffeeDecorator {
public SugarDecorator(ICoffee c) : base(c) {}
public override double Cost => Coffee.Cost + 0.2;
public override string Description => Coffee.Description + ", Sugar";
}
class SimpleCoffee
def cost = 2.0
def description = "Simple coffee"
end
class CoffeeDecorator
def initialize(coffee)
@coffee = coffee
end
def cost
@coffee.cost
end
def description
@coffee.description
end
end
class MilkDecorator < CoffeeDecorator
def cost
@coffee.cost + 0.5
end
def description
"#{@coffee.description}, Milk"
end
end
class SugarDecorator < CoffeeDecorator
def cost
@coffee.cost + 0.2
end
def description
"#{@coffee.description}, Sugar"
end
end
# Usage
coffee = SimpleCoffee.new
coffee = MilkDecorator.new(coffee)
coffee = SugarDecorator.new(coffee)
puts "#{coffee.description} = $#{coffee.cost}"
Behavioural Patterns
Observer
Define dependency so when one object changes, all dependents are notified.
from typing import Callable, List, Dict
from collections import defaultdict
class EventBus:
def __init__(self):
self._listeners: Dict[str, List[Callable]] = defaultdict(list)
def subscribe(self, event: str, callback: Callable) -> None:
self._listeners[event].append(callback)
def publish(self, event: str, data: dict = None) -> None:
for callback in self._listeners[event]:
callback(data or {})
# Usage
bus = EventBus()
bus.subscribe("enemy_killed", lambda d: print(f"Enemy killed: {d.get('enemy', 'unknown')}"))
bus.publish("enemy_killed", {"enemy": "goblin", "xp": 10})
#include <functional>
#include <unordered_map>
#include <vector>
#include <any>
class EventBus {
std::unordered_map<std::string, std::vector<std::function<void(const std::any&)>>> listeners_;
public:
template<typename F>
void subscribe(const std::string& event, F&& cb) {
listeners_[event].push_back(std::forward<F>(cb));
}
void publish(const std::string& event, const std::any& data = {}) {
for (auto& cb : listeners_[event]) cb(data);
}
};
// Usage
EventBus bus;
bus.subscribe("enemy_killed", [](const std::any& data) {
auto d = std::any_cast<std::map<std::string, int>>(data);
std::cout << "Enemy killed: " << d.at("enemy") << " xp: " << d.at("xp") << "\n";
});
bus.publish("enemy_killed", std::map<std::string, int>{{"enemy", 0}, {"xp", 10}});
import java.util.*;
import java.util.function.Consumer;
public class EventBus {
private final Map<String, List<Consumer<Map<String, Object>>>> listeners = new HashMap<>();
public void subscribe(String event, Consumer<Map<String, Object>> cb) {
listeners.computeIfAbsent(event, k -> new ArrayList<>()).add(cb);
}
public void publish(String event, Map<String, Object> data) {
for (var cb : listeners.getOrDefault(event, List.of())) cb.accept(data);
}
}
// Usage
EventBus bus = new EventBus();
bus.subscribe("enemy_killed", data ->
System.out.println("Enemy killed: " + data.get("enemy") + " xp: " + data.get("xp")));
bus.publish("enemy_killed", Map.of("enemy", "goblin", "xp", 10));
using System;
using System.Collections.Generic;
public class EventBus {
private readonly Dictionary<string, List<Action<Dictionary<string, object>>>> _listeners = new();
public void Subscribe(string evt, Action<Dictionary<string, object>> cb) {
if (!_listeners.TryGetValue(evt, out var list))
_listeners[evt] = new List<Action<Dictionary<string, object>>>();
_listeners[evt].Add(cb);
}
public void Publish(string evt, Dictionary<string, object> data = null) {
if (_listeners.TryGetValue(evt, out var list))
foreach (var cb in list) cb(data ?? new());
}
}
// Usage
var bus = new EventBus();
bus.Subscribe("enemy_killed", data =>
Console.WriteLine($"Enemy killed: {data["enemy"]} xp: {data["xp"]}"));
bus.Publish("enemy_killed", new Dictionary<string, object> { ["enemy"] = "goblin", ["xp"] = 10 });
class EventBus
def initialize
@listeners = Hash.new { |hash, key| hash[key] = [] }
end
def subscribe(event, &callback)
@listeners[event] << callback
end
def publish(event, data = {})
@listeners[event].each { |callback| callback.call(data) }
end
end
# Usage
bus = EventBus.new
bus.subscribe("enemy_killed") { |d| puts "Enemy killed: #{d.fetch(:enemy, 'unknown')}" }
bus.publish("enemy_killed", enemy: "goblin", xp: 10)
Dathan, B. & Ramnath, S. (2015). Object-Oriented Analysis, Design and Implementation: An Integrated Approach (2nd ed.). Springer/Universities Press. Chapter 10, "Modelling with Finite State Machines" — works through a Java Observer implementation (a Clock event source implemented as a Singleton, with listeners implementing an update method) for a microwave-oven case study, and discusses the same Singleton/Observer/Factory/Adapter patterns used above.
Strategy
Define family of algorithms, encapsulate each, make interchangeable.
from abc import ABC, abstractmethod
class CompressionStrategy(ABC):
@abstractmethod
def compress(self, data: str) -> str:
pass
class ZipStrategy(CompressionStrategy):
def compress(self, data: str) -> str:
return f"zip:{data}"
class GzipStrategy(CompressionStrategy):
def compress(self, data: str) -> str:
return f"gzip:{data}"
class Compressor:
def __init__(self, strategy: CompressionStrategy):
self.strategy = strategy
def compress(self, data: str) -> str:
return self.strategy.compress(data)
def set_strategy(self, strategy: CompressionStrategy) -> None:
self.strategy = strategy
# Usage — swap at runtime!
c = Compressor(ZipStrategy())
print(c.compress("data")) # "zip:data"
c.set_strategy(GzipStrategy())
print(c.compress("data")) # "gzip:data"
#include <memory>
#include <string>
class CompressionStrategy {
public:
virtual std::string compress(const std::string& data) = 0;
virtual ~CompressionStrategy() = default;
};
class ZipStrategy : public CompressionStrategy {
public:
std::string compress(const std::string& data) override { return "zip:" + data; }
};
class GzipStrategy : public CompressionStrategy {
public:
std::string compress(const std::string& data) override { return "gzip:" + data; }
};
class Compressor {
std::unique_ptr<CompressionStrategy> strategy_;
public:
explicit Compressor(std::unique_ptr<CompressionStrategy> s) : strategy_(std::move(s)) {}
std::string compress(const std::string& data) { return strategy_->compress(data); }
void setStrategy(std::unique_ptr<CompressionStrategy> s) { strategy_ = std::move(s); }
};
// Usage — swap at runtime!
Compressor c(std::make_unique<ZipStrategy>());
c.compress("data"); // "zip:data"
c.setStrategy(std::make_unique<GzipStrategy>());
c.compress("data"); // "gzip:data"
interface CompressionStrategy {
String compress(String data);
}
class ZipStrategy implements CompressionStrategy {
public String compress(String data) { return "zip:" + data; }
}
class GzipStrategy implements CompressionStrategy {
public String compress(String data) { return "gzip:" + data; }
}
public final class Compressor {
private CompressionStrategy strategy;
public Compressor(CompressionStrategy s) { this.strategy = s; }
public String compress(String data) { return strategy.compress(data); }
public void setStrategy(CompressionStrategy s) { this.strategy = s; }
}
// Usage — swap at runtime!
Compressor c = new Compressor(new ZipStrategy());
c.compress("data"); // "zip:data"
c.setStrategy(new GzipStrategy());
c.compress("data"); // "gzip:data"
public interface ICompressionStrategy {
string Compress(string data);
}
public sealed class ZipStrategy : ICompressionStrategy {
public string Compress(string data) => "zip:" + data;
}
public sealed class GzipStrategy : ICompressionStrategy {
public string Compress(string data) => "gzip:" + data;
}
public sealed class Compressor {
private ICompressionStrategy _strategy;
public Compressor(ICompressionStrategy s) => _strategy = s;
public string Compress(string data) => _strategy.Compress(data);
public void SetStrategy(ICompressionStrategy s) => _strategy = s;
}
// Usage — swap at runtime!
var c = new Compressor(new ZipStrategy());
c.Compress("data"); // "zip:data"
c.SetStrategy(new GzipStrategy());
c.Compress("data"); // "gzip:data"
class ZipStrategy
def compress(data)
"zip:#{data}"
end
end
class GzipStrategy
def compress(data)
"gzip:#{data}"
end
end
class Compressor
attr_writer :strategy
def initialize(strategy)
@strategy = strategy
end
def compress(data)
@strategy.compress(data)
end
end
# Usage — swap at runtime!
c = Compressor.new(ZipStrategy.new)
puts c.compress("data") # "zip:data"
c.strategy = GzipStrategy.new
puts c.compress("data") # "gzip:data"
Related Topics
- Inheritance & Composition — the "favour composition over inheritance" rule this page's Strategy pattern demonstrates in practice.
- Class Diagrams: Design Before Code — the UML vocabulary (interfaces, generalization) that a pattern's own structure diagram is drawn in.
- SOLID Principles — the design principles many of these patterns exist specifically to satisfy.
- Game Programming Patterns — the same GoF pattern vocabulary applied to a real-time, performance-critical domain, with patterns like Command doing double duty for replay and AI.
References
Alexander, C., Ishikawa, S., & Silverstein, M. (1977). A Pattern Language: Towns, Buildings, Construction. Oxford University Press, p. x. Held by the University of Reading Library. ↩
Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. Held by the University of Reading Library. ↩