Files
2026-07-13 21:36:32 +08:00

581 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 创建型设计模式
创建型模式处理对象的创建机制,试图以适合当前情境的方式创建对象。
---
## 1. 单例模式(Singleton Pattern
### 问题
你需要一个类的唯一实例(例如,数据库连接、配置管理器、日志记录器)。
### 反面示例
```python
# 可以创建多个实例
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 — 不同的实例!
```
### 解决方案
```python
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 实现
```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
### 问题
你需要在未指定具体类的情况下创建对象。创建逻辑复杂或依赖于条件。
### 反面示例
```python
# 客户端代码需要了解所有具体类
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()
# 添加新宠物类型需要修改此函数!
```
### 解决方案
```python
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 实现
```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 主题工厂
```python
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
### 问题
你需要逐步构建复杂对象。构造函数参数过多。
### 反面示例
```python
# 构造函数参数过多
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)
```
### 解决方案
```python
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 实现
```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
### 问题
你需要复制现有对象,而不让代码依赖于它们的类。
### 解决方案
```python
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 实现
```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. 过度使用单例
```python
# 不要把所有东西都做成单例
class MathUtils(Singleton): # 糟糕 —— 直接使用模块即可!
@staticmethod
def add(a, b):
return a + b
# 应使用模块级函数
def add(a, b):
return a + b
```
### 2. 上帝工厂
```python
# 不要用一个工厂处理所有事情
class GodFactory:
def create_user(self): ...
def create_product(self): ...
def create_order(self): ...
# ... 还有 50 多个方法
# 应按不同关注点使用独立的工厂
class UserFactory: ...
class ProductFactory: ...
class OrderFactory: ...
```
### 3. 过早抽象
```python
# 不要在简单情况下创建工厂
class DogFactory:
@staticmethod
def create():
return Dog() # 只有一个简单的类
# 应直接实例化
dog = Dog()
```
---
## 关键要点
1. **单例模式**:唯一实例,全局访问
2. **工厂模式**:将对象创建与使用解耦
3. **抽象工厂模式**:一组相关的对象家族
4. **构建器模式**:逐步构建复杂对象
5. **原型模式**:克隆现有对象
**请记住**:在模式确实能解决实际问题时再使用。不要在模式不适用时强行套用!