581 lines
13 KiB
Markdown
581 lines
13 KiB
Markdown
# 创建型设计模式
|
||
|
||
创建型模式处理对象的创建机制,试图以适合当前情境的方式创建对象。
|
||
|
||
---
|
||
|
||
## 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. **原型模式**:克隆现有对象
|
||
|
||
**请记住**:在模式确实能解决实际问题时再使用。不要在模式不适用时强行套用!
|