13 KiB
13 KiB
创建型设计模式
创建型模式处理对象的创建机制,试图以适合当前情境的方式创建对象。
1. 单例模式(Singleton Pattern)
问题
你需要一个类的唯一实例(例如,数据库连接、配置管理器、日志记录器)。
反面示例
# 可以创建多个实例
class DatabaseConnection:
def __init__(self):
self.connection = self.connect()
def connect(self):
print("Connecting to database...")
return "DB Connection"
# 问题:创建了多个连接
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # False — 不同的实例!
解决方案
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
class DatabaseConnection(Singleton):
def __init__(self):
if not hasattr(self, 'initialized'):
self.connection = self.connect()
self.initialized = True
def connect(self):
print("Connecting to database...")
return "DB Connection"
# 使用示例
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True — 同一个实例!
JavaScript 实现
class DatabaseConnection {
constructor() {
if (DatabaseConnection.instance) {
return DatabaseConnection.instance;
}
this.connection = this.connect();
DatabaseConnection.instance = this;
}
connect() {
console.log("Connecting to database...");
return "DB Connection";
}
}
// 使用示例
const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();
console.log(db1 === db2); // true
何时使用
- 适用:日志记录器、配置管理、连接池、缓存
- 不适用:当你需要多个实例时,或用于简单工具类(改用模块)
优缺点
✅ 对唯一实例的受控访问 ✅ 延迟初始化(Lazy initialization) ❌ 全局状态(可能增加测试难度) ❌ 可能违反单一职责原则(Single Responsibility Principle)
2. 工厂模式(Factory Pattern)
问题
你需要在未指定具体类的情况下创建对象。创建逻辑复杂或依赖于条件。
反面示例
# 客户端代码需要了解所有具体类
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
# 客户端必须知道实例化哪个类
def get_pet(pet_type):
if pet_type == "dog":
return Dog()
elif pet_type == "cat":
return Cat()
# 添加新宠物类型需要修改此函数!
解决方案
from abc import ABC, abstractmethod
# 抽象产品
class Animal(ABC):
@abstractmethod
def speak(self):
pass
# 具体产品
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class Bird(Animal):
def speak(self):
return "Tweet!"
# 工厂
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
animals = {
'dog': Dog,
'cat': Cat,
'bird': Bird
}
animal_class = animals.get(animal_type.lower())
if animal_class:
return animal_class()
raise ValueError(f"Unknown animal type: {animal_type}")
# 使用示例
factory = AnimalFactory()
pet = factory.create_animal('dog')
print(pet.speak()) # Woof!
JavaScript 实现
class Animal {
speak() {
throw new Error("Method must be implemented");
}
}
class Dog extends Animal {
speak() {
return "Woof!";
}
}
class Cat extends Animal {
speak() {
return "Meow!";
}
}
class AnimalFactory {
static createAnimal(animalType) {
const animals = {
dog: Dog,
cat: Cat
};
const AnimalClass = animals[animalType.toLowerCase()];
if (AnimalClass) {
return new AnimalClass();
}
throw new Error(`Unknown animal type: ${animalType}`);
}
}
// 使用示例
const pet = AnimalFactory.createAnimal('dog');
console.log(pet.speak()); // Woof!
何时使用
- 适用:当你事先不知道确切类型时,或创建逻辑较为复杂
- 不适用:用于没有变化的简单对象创建
优缺点
✅ 客户端与产品之间的松耦合 ✅ 易于添加新产品(开闭原则,Open/Closed Principle) ✅ 集中化的创建逻辑 ❌ 可能引入大量类
3. 抽象工厂模式(Abstract Factory Pattern)
问题
你需要在未指定具体类的情况下创建一组相关的对象家族。
示例:UI 主题工厂
from abc import ABC, abstractmethod
# 抽象产品
class Button(ABC):
@abstractmethod
def render(self):
pass
class Checkbox(ABC):
@abstractmethod
def render(self):
pass
# 具体产品 —— 浅色主题
class LightButton(Button):
def render(self):
return "Rendering light button"
class LightCheckbox(Checkbox):
def render(self):
return "Rendering light checkbox"
# 具体产品 —— 深色主题
class DarkButton(Button):
def render(self):
return "Rendering dark button"
class DarkCheckbox(Checkbox):
def render(self):
return "Rendering dark checkbox"
# 抽象工厂
class UIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
# 具体工厂
class LightThemeFactory(UIFactory):
def create_button(self):
return LightButton()
def create_checkbox(self):
return LightCheckbox()
class DarkThemeFactory(UIFactory):
def create_button(self):
return DarkButton()
def create_checkbox(self):
return DarkCheckbox()
# 客户端代码
def create_ui(factory: UIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()
return button.render(), checkbox.render()
# 使用示例
light_factory = LightThemeFactory()
print(create_ui(light_factory))
dark_factory = DarkThemeFactory()
print(create_ui(dark_factory))
何时使用
- 适用:当你需要一组相关的对象协同工作时
- 不适用:当你只有一个产品家族时
4. 构建器模式(Builder Pattern)
问题
你需要逐步构建复杂对象。构造函数参数过多。
反面示例
# 构造函数参数过多
class Pizza:
def __init__(self, size, cheese=False, pepperoni=False,
mushrooms=False, onions=False, bacon=False,
ham=False, pineapple=False):
self.size = size
self.cheese = cheese
self.pepperoni = pepperoni
# ... 大量参数
# 难以阅读,容易出错
pizza = Pizza(12, True, True, False, True, False, True, False)
解决方案
class Pizza:
def __init__(self, size):
self.size = size
self.cheese = False
self.pepperoni = False
self.mushrooms = False
self.onions = False
self.bacon = False
def __str__(self):
toppings = []
if self.cheese:
toppings.append("cheese")
if self.pepperoni:
toppings.append("pepperoni")
if self.mushrooms:
toppings.append("mushrooms")
if self.onions:
toppings.append("onions")
if self.bacon:
toppings.append("bacon")
return f"{self.size}\" pizza with {', '.join(toppings)}"
class PizzaBuilder:
def __init__(self, size):
self.pizza = Pizza(size)
def add_cheese(self):
self.pizza.cheese = True
return self
def add_pepperoni(self):
self.pizza.pepperoni = True
return self
def add_mushrooms(self):
self.pizza.mushrooms = True
return self
def add_onions(self):
self.pizza.onions = True
return self
def add_bacon(self):
self.pizza.bacon = True
return self
def build(self):
return self.pizza
# 使用示例 —— 可读性大大提升!
pizza = (PizzaBuilder(12)
.add_cheese()
.add_pepperoni()
.add_mushrooms()
.build())
print(pizza) # 12" pizza with cheese, pepperoni, mushrooms
JavaScript 实现
class Pizza {
constructor(size) {
this.size = size;
this.toppings = [];
}
toString() {
return `${this.size}" pizza with ${this.toppings.join(', ')}`;
}
}
class PizzaBuilder {
constructor(size) {
this.pizza = new Pizza(size);
}
addCheese() {
this.pizza.toppings.push('cheese');
return this;
}
addPepperoni() {
this.pizza.toppings.push('pepperoni');
return this;
}
addMushrooms() {
this.pizza.toppings.push('mushrooms');
return this;
}
build() {
return this.pizza;
}
}
// 使用示例
const pizza = new PizzaBuilder(12)
.addCheese()
.addPepperoni()
.addMushrooms()
.build();
console.log(pizza.toString());
何时使用
- 适用:构造函数参数多、需要逐步构建、需要不可变对象
- 不适用:参数少的简单对象
优缺点
✅ 可读性强的流畅接口(Fluent Interface) ✅ 对构建过程的精细控制 ✅ 可以创建不同的表示形式 ❌ 代码量增加(需要构建器类)
5. 原型模式(Prototype Pattern)
问题
你需要复制现有对象,而不让代码依赖于它们的类。
解决方案
import copy
class Prototype:
def clone(self):
"""对象的深拷贝。"""
return copy.deepcopy(self)
class Shape(Prototype):
def __init__(self, shape_type, color):
self.shape_type = shape_type
self.color = color
self.coordinates = []
def __str__(self):
return f"{self.color} {self.shape_type} at {self.coordinates}"
# 使用示例
original = Shape("Circle", "Red")
original.coordinates = [10, 20]
# 克隆
clone = original.clone()
clone.color = "Blue"
clone.coordinates = [30, 40]
print(original) # Red Circle at [10, 20]
print(clone) # Blue Circle at [30, 40]
JavaScript 实现
class Shape {
constructor(shapeType, color) {
this.shapeType = shapeType;
this.color = color;
this.coordinates = [];
}
clone() {
const cloned = Object.create(Object.getPrototypeOf(this));
cloned.shapeType = this.shapeType;
cloned.color = this.color;
cloned.coordinates = [...this.coordinates];
return cloned;
}
toString() {
return `${this.color} ${this.shapeType} at ${this.coordinates}`;
}
}
// 使用示例
const original = new Shape("Circle", "Red");
original.coordinates = [10, 20];
const clone = original.clone();
clone.color = "Blue";
clone.coordinates = [30, 40];
console.log(original.toString()); // Red Circle at 10,20
console.log(clone.toString()); // Blue Circle at 30,40
何时使用
- 适用:对象创建成本高,需要大量相似对象
- 不适用:简单对象,浅拷贝即可满足需求
模式选择指南
| 模式 | 适用场景 | 典型用例 |
|---|---|---|
| 单例模式(Singleton) | 需要唯一实例 | 日志记录器、配置管理、数据库连接池 |
| 工厂模式(Factory) | 编译时不知道具体类 | 插件系统、文档类型 |
| 抽象工厂模式(Abstract Factory) | 需要一组相关的对象 | UI 主题、跨平台应用 |
| 构建器模式(Builder) | 参数众多的复杂构建过程 | 查询构建器、文档构建器 |
| 原型模式(Prototype) | 创建成本高,需要副本 | 游戏实体、图形编辑器 |
应避免的反模式
1. 过度使用单例
# 不要把所有东西都做成单例
class MathUtils(Singleton): # 糟糕 —— 直接使用模块即可!
@staticmethod
def add(a, b):
return a + b
# 应使用模块级函数
def add(a, b):
return a + b
2. 上帝工厂
# 不要用一个工厂处理所有事情
class GodFactory:
def create_user(self): ...
def create_product(self): ...
def create_order(self): ...
# ... 还有 50 多个方法
# 应按不同关注点使用独立的工厂
class UserFactory: ...
class ProductFactory: ...
class OrderFactory: ...
3. 过早抽象
# 不要在简单情况下创建工厂
class DogFactory:
@staticmethod
def create():
return Dog() # 只有一个简单的类
# 应直接实例化
dog = Dog()
关键要点
- 单例模式:唯一实例,全局访问
- 工厂模式:将对象创建与使用解耦
- 抽象工厂模式:一组相关的对象家族
- 构建器模式:逐步构建复杂对象
- 原型模式:克隆现有对象
请记住:在模式确实能解决实际问题时再使用。不要在模式不适用时强行套用!