创建型模式关注对象的创建机制,将对象的实例化过程与使用过程解耦,提高代码的灵活性和复用性。
1. 单例模式(Singleton)
意图
确保一个类只有一个实例,并提供一个全局访问点。
问题
某些类(如配置管理器、日志记录器)只需一个实例。如果存在多个实例,会导致状态不一致或资源浪费。
解决方案
- 将构造函数私有化(语言支持时),使外界无法直接创建实例。
- 类内部维护一个静态私有成员变量,保存唯一实例。
- 提供一个静态公有方法(如
getInstance())返回该实例。 - 第一次调用时创建实例,后续直接返回已有实例(懒加载)。
结构(UML)
┌─────────────────┐
│ Singleton │
├─────────────────┤
│ - instance │ (静态私有)
├─────────────────┤
│ + getInstance() │
│ - Singleton() │
└─────────────────┘
参与者
- Singleton:定义
getInstance方法,负责创建和管理自己的唯一实例。
协作
- 客户端通过
Singleton.getInstance()获取实例,而不是直接new Singleton()。
适用性
- 类只能有一个实例,且客户端需要从全局单一访问点访问它。
- 该唯一实例需要通过子类化扩展,且客户端无需修改代码即可使用扩展实例。
Python 示例
# 模块级单例(利用 Python 模块的天然单例特性)
class Singleton:
def __init__(self):
self.value = 0
_instance = Singleton()
def get_instance():
return _instance
# 使用
s1 = get_instance()
s2 = get_instance()
assert s1 is s22. 工厂方法模式(Factory Method)
意图
定义一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法将实例化延迟到子类。
问题
一个类需要创建对象,但具体类型在编译时无法确定,或者需要将创建逻辑与使用逻辑解耦。
解决方案
- Creator 类声明一个抽象工厂方法,返回产品类型。
- ConcreteCreator 子类实现该工厂方法,返回具体产品实例。
- 客户端依赖产品接口和创建者接口,无需知道具体产品类名。
结构(UML)
┌─────────────┐ ┌─────────────┐
│ Product │ │ Creator │
├─────────────┤ ├─────────────┤
│ + operation │ │ + factoryMethod() │
└─────────────┘ │ + someOperation() │
△ └─────────────┘
│ △
┌─────────────┐ ┌─────────────┐
│ ConcreteProduct│ │ ConcreteCreator│
├─────────────┤ ├─────────────┤
│ + operation │ │ + factoryMethod() │
└─────────────┘ └─────────────┘
参与者
- Product:定义产品对象的公共接口。
- ConcreteProduct:实现 Product 接口的具体产品类。
- Creator:声明工厂方法,通常还包含调用工厂方法的核心业务逻辑。
- ConcreteCreator:实现工厂方法,返回具体产品实例。
协作
- 客户端调用 Creator 的
someOperation(),后者调用工厂方法创建产品,然后使用产品。 - 不同 ConcreteCreator 返回不同 ConcreteProduct,从而改变行为。
适用性
- 一个类无法预知它必须创建的对象类型。
- 类希望其子类决定创建什么对象。
- 将创建逻辑与使用逻辑分离,符合开闭原则。
Python 示例
from abc import ABC, abstractmethod
# Product
class Animal(ABC):
@abstractmethod
def speak(self): pass
# Concrete Products
class Dog(Animal):
def speak(self): return "Woof"
class Cat(Animal):
def speak(self): return "Meow"
# Creator
class AnimalFactory(ABC):
@abstractmethod
def create_animal(self) -> Animal: pass
def make_sound(self):
animal = self.create_animal()
print(animal.speak())
# Concrete Creators
class DogFactory(AnimalFactory):
def create_animal(self) -> Animal: return Dog()
class CatFactory(AnimalFactory):
def create_animal(self) -> Animal: return Cat()
# Client
def client_code(factory: AnimalFactory):
factory.make_sound()
client_code(DogFactory()) # Woof
client_code(CatFactory()) # Meow3. 抽象工厂模式(Abstract Factory)
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
问题
需要创建一组产品(如 UI 组件:按钮、复选框),它们有多种风格(如 Windows、Mac)。客户端不应依赖具体类。
解决方案
- 声明抽象工厂接口,其中包含每个产品类型的创建方法(如
createButton,createCheckbox)。 - 为每种产品族(如 Windows 风格)实现具体工厂类,每个工厂负责创建该族所有产品。
- 客户端接收抽象工厂接口,运行时注入具体工厂,从而创建整个产品族。
结构(UML)
┌─────────────────┐
│ AbstractFactory │
├─────────────────┤
│ + createButton()│
│ + createCheckbox()│
└─────────────────┘
△
┌──────────┴──────────┐
┌─────────────┐ ┌─────────────┐
│ WinFactory │ │ MacFactory │
├─────────────┤ ├─────────────┤
│ + createButton() │ │ + createButton() │
│ + createCheckbox()│ │ + createCheckbox()│
└─────────────┘ └─────────────┘
参与者
- AbstractFactory:声明创建抽象产品对象的操作。
- ConcreteFactory:实现创建具体产品对象的操作。
- AbstractProduct:为一种产品类型声明接口。
- ConcreteProduct:定义被具体工厂创建的产品对象。
- Client:仅使用 AbstractFactory 和 AbstractProduct 接口。
协作
- 客户端创建具体工厂对象,然后通过该工厂创建所需产品。
- 产品系列通过同一个工厂保持一致(例如 Windows 工厂创建的所有控件都是 Windows 风格)。
适用性
- 系统独立于产品的创建、组合和表示。
- 系统需要配置多个产品系列之一。
- 强制相关产品对象一起使用。
Python 示例
from abc import ABC, abstractmethod
# Abstract Products
class Button(ABC):
@abstractmethod
def paint(self): pass
class Checkbox(ABC):
@abstractmethod
def paint(self): pass
# Concrete Products for Windows
class WinButton(Button):
def paint(self): print("Windows button")
class WinCheckbox(Checkbox):
def paint(self): print("Windows checkbox")
# Concrete Products for Mac
class MacButton(Button):
def paint(self): print("Mac button")
class MacCheckbox(Checkbox):
def paint(self): print("Mac checkbox")
# Abstract Factory
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button: pass
@abstractmethod
def create_checkbox(self) -> Checkbox: pass
# Concrete Factories
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()
# Client
def render_ui(factory: GUIFactory):
btn = factory.create_button()
chk = factory.create_checkbox()
btn.paint()
chk.paint()
# 根据平台选择工厂
import sys
factory = WinFactory() if sys.platform == "win32" else MacFactory()
render_ui(factory)4. 建造者模式(Builder)
意图
将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
问题
创建一个由多个部分组成的复杂对象(如文档、计算机),构造过程应独立于这些部分的装配方式。
解决方案
- Builder 接口声明构建产品各部分的方法。
- ConcreteBuilder 实现这些方法,并提供一个返回最终产品的方法。
- Director 负责按照特定顺序调用 Builder 的方法来构建产品。
- 客户端通过 Director 与 Builder 交互,不直接接触产品构造细节。
结构(UML)
┌─────────────┐ ┌─────────────┐
│ Director │ │ Builder │
├─────────────┤ ├─────────────┤
│ + construct()│─────▶│ + buildPartA()│
└─────────────┘ │ + buildPartB()│
│ + getResult() │
└─────────────┘
△
┌─────────────┐
│ConcreteBuilder│
├─────────────┤
│ + buildPartA()│
│ + buildPartB()│
│ + getResult() │
└─────────────┘
参与者
- Builder:为创建产品各个部分声明接口。
- ConcreteBuilder:实现 Builder 接口,构造并装配产品各部分,提供获取产品的接口。
- Director:构造一个使用 Builder 接口的对象,定义构建产品的步骤。
- Product:表示被构造的复杂对象,通常包含多个部分。
协作
- 客户端创建 Director 和 ConcreteBuilder,将 Builder 交给 Director。
- Director 调用 Builder 的方法构建产品,客户端从 Builder 获取最终产品。
适用性
- 创建复杂对象的算法应独立于该对象的组成部分及其装配方式。
- 构造过程允许被构造的对象有不同的表示。
Python 示例
# Product
class Computer:
def __init__(self):
self.cpu = None
self.ram = None
self.storage = None
def __str__(self):
return f"Computer(cpu={self.cpu}, ram={self.ram}, storage={self.storage})"
# Builder
class ComputerBuilder:
def __init__(self):
self.computer = Computer()
def set_cpu(self, cpu): self.computer.cpu = cpu; return self
def set_ram(self, ram): self.computer.ram = ram; return self
def set_storage(self, storage): self.computer.storage = storage; return self
def build(self): return self.computer
# Director
class Director:
def __init__(self, builder: ComputerBuilder):
self._builder = builder
def build_gaming_computer(self):
return self._builder.set_cpu("Intel i9").set_ram("32GB").set_storage("1TB SSD").build()
def build_office_computer(self):
return self._builder.set_cpu("Intel i5").set_ram("16GB").set_storage("512GB SSD").build()
# Client
builder = ComputerBuilder()
director = Director(builder)
gaming_pc = director.build_gaming_computer()
office_pc = director.build_office_computer()
print(gaming_pc)
print(office_pc)5. 原型模式(Prototype)
意图
用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象。
问题
创建对象成本较高(如数据库查询、复杂计算),或者需要避免子类化。
解决方案
- 提供一个克隆接口(如
clone()方法),允许对象复制自身。 - 客户端通过复制原型对象来创建新对象,而不是调用构造函数。
结构(UML)
┌─────────────┐
│ Prototype │
├─────────────┤
│ + clone() │
└─────────────┘
△
┌─────────────┐
│ConcretePrototype│
├─────────────┤
│ + clone() │
└─────────────┘
参与者
- Prototype:声明克隆自身的接口。
- ConcretePrototype:实现克隆方法,复制自身的数据。
- Client:通过克隆原型创建新对象。
协作
- 客户端请求原型对象克隆自身,得到一个新实例,该实例与原型独立但内容相同。
适用性
- 系统应独立于产品的创建、组合和表示。
- 实例化类在运行时指定(如动态加载)。
- 避免创建与产品类层次平行的工厂类层次。
- 类的实例只有少数几种状态组合。
Python 示例
import copy
# Prototype
class Prototype:
def clone(self):
return copy.deepcopy(self)
# Concrete Prototype
class Document(Prototype):
def __init__(self, title, content, metadata):
self.title = title
self.content = content
self.metadata = metadata # 例如字典,需要深拷贝
def __str__(self):
return f"Document(title={self.title}, content={self.content[:10]}..., metadata={self.metadata})"
# Client
original = Document("Report", "This is the content...", {"author": "Alice", "version": 1})
cloned = original.clone()
cloned.title = "Report Copy"
cloned.metadata["version"] = 2
print(original)
print(cloned)
# 修改克隆不影响原对象(深拷贝)创建型模式总结
| 模式 | 核心思想 | 解决的主要问题 |
|---|---|---|
| 单例 | 唯一实例 + 全局访问点 | 确保一个类只有一个实例 |
| 工厂方法 | 定义创建接口,子类决定具体类型 | 将对象的创建延迟到子类 |
| 抽象工厂 | 创建一系列相关产品族 | 产品族的替换与统一创建 |
| 建造者 | 分步构建复杂对象,同一过程多种表示 | 复杂对象的构造与表示分离 |
| 原型 | 通过复制原型创建新对象 | 避免昂贵构造或重复初始化 |