设计模式实现
概述
应用经过验证的设计模式来创建可维护、可扩展和可测试的代码架构。
何时使用
- 解决常见的架构问题
- 使代码更加可维护和可测试
- 实现可扩展的插件系统
- 解耦组件
- 遵循SOLID原则
- 代码审查中识别架构问题
常见设计模式
1. 单例模式
确保一个类只有一个实例,并提供全局访问。
class DatabaseConnection {
private static instance: DatabaseConnection;
private connection: any;
private constructor() {
this.connection = this.createConnection();
}
public static getInstance(): DatabaseConnection {
if (!DatabaseConnection.instance) {
DatabaseConnection.instance = new DatabaseConnection();
}
return DatabaseConnection.instance;
}
private createConnection() {
return { /* 连接逻辑 */ };
}
}
// 使用
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();
// db1 === db2(同一实例)
2. 工厂模式
创建对象而不指定确切的类。
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount: float) -> bool:
pass
class StripeProcessor(PaymentProcessor):
def process_payment(self, amount: float) -> bool:
# Stripe特定逻辑
return True
class PayPalProcessor(PaymentProcessor):
def process_payment(self, amount: float) -> bool:
# PayPal特定逻辑
return True
class PaymentProcessorFactory:
@staticmethod
def create_processor(processor_type: str) -> PaymentProcessor:
if processor_type == 'stripe':
return StripeProcessor()
elif processor_type == 'paypal':
return PayPalProcessor()
else:
raise ValueError(f'未知处理器: {processor_type}')
# 使用
processor = PaymentProcessorFactory.create_processor('stripe')
processor.process_payment(100.00)
3. 观察者模式
定义一对多的依赖关系,用于事件通知。
class Subject {
constructor() {
this.observers = [];
}
attach(observer) {
this.observers.push(observer);
}
detach(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
update(data) {
console.log('收到更新:', data);
}
}
// 使用
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.attach(observer1);
subject.attach(observer2);
subject.notify({ event: 'data_changed' });
4. 策略模式
定义一系列算法,并使它们可以互换。
interface CompressionStrategy {
byte[] compress(byte[] data);
}
class ZipCompression implements CompressionStrategy {
public byte[] compress(byte[] data) {
// ZIP压缩逻辑
return data;
}
}
class GzipCompression implements CompressionStrategy {
public byte[] compress(byte[] data) {
// GZIP压缩逻辑
return data;
}
}
class FileCompressor {
private CompressionStrategy strategy;
public FileCompressor(CompressionStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(CompressionStrategy strategy) {
this.strategy = strategy;
}
public byte[] compressFile(byte[] data) {
return strategy.compress(data);
}
}
// 使用
FileCompressor compressor = new FileCompressor(new ZipCompression());
compressor.compressFile(fileData);
// 在运行时更改策略
compressor.setStrategy(new GzipCompression());
compressor.compressFile(fileData);
5. 装饰器模式
动态地向对象添加职责。
interface Coffee {
cost(): number;
description(): string;
}
class SimpleCoffee implements Coffee {
cost(): number {
return 5;
}
description(): string {
return '简单咖啡';
}
}
class MilkDecorator implements Coffee {
constructor(private coffee: Coffee) {}
cost(): number {
return this.coffee.cost() + 2;
}
description(): string {
return this.coffee.description() + ',牛奶';
}
}
class SugarDecorator implements Coffee {
constructor(private coffee: Coffee) {}
cost(): number {
return this.coffee.cost() + 1;
}
description(): string {
return this.coffee.description() + ',糖';
}
}
// 使用
let coffee: Coffee = new SimpleCoffee();
console.log(coffee.cost()); // 5
coffee = new MilkDecorator(coffee);
console.log(coffee.cost()); // 7
coffee = new SugarDecorator(coffee);
console.log(coffee.cost()); // 8
console.log(coffee.description()); // "简单咖啡,牛奶,糖"
6. 仓库模式
抽象数据访问逻辑。
from abc import ABC, abstractmethod
from typing import List, Optional
class UserRepository(ABC):
@abstractmethod
def find_by_id(self, user_id: int) -> Optional[User]:
pass
@abstractmethod
def find_all(self) -> List[User]:
pass
@abstractmethod
def save(self, user: User) -> User:
pass
@abstractmethod
def delete(self, user_id: int) -> bool:
pass
class DatabaseUserRepository(UserRepository):
def __init__(self, db_connection):
self.db = db_connection
def find_by_id(self, user_id: int) -> Optional[User]:
result = self.db.query('SELECT * FROM users WHERE id = ?', user_id)
return User.from_dict(result) if result else None
def find_all(self) -> List[User]:
results = self.db.query('SELECT * FROM users')
return [User.from_dict(r) for r in results]
def save(self, user: User) -> User:
self.db.execute('INSERT INTO users (...) VALUES (...)', user.to_dict())
return user
def delete(self, user_id: int) -> bool:
return self.db.execute('DELETE FROM users WHERE id = ?', user_id)
7. 依赖注入
通过注入依赖来反转控制。
// 不好:硬编码依赖
class OrderService {
private db = new MySQLDatabase(); // 紧密耦合
private email = new GmailService(); // 紧密耦合
createOrder(order: Order) {
this.db.save(order);
this.email.send(order.customer_email, '订单已创建');
}
}
// 好:依赖注入
interface Database {
save(entity: any): void;
}
interface EmailService {
send(to: string, subject: string): void;
}
class OrderService {
constructor(
private db: Database,
private email: EmailService
) {}
createOrder(order: Order) {
this.db.save(order);
this.email.send(order.customer_email, '订单已创建');
}
}
// 使用 - 使用mocks容易测试
const service = new OrderService(
new MySQLDatabase(),
new GmailService()
);
// 使用mocks进行测试
const testService = new OrderService(
new MockDatabase(),
new MockEmailService()
);
最佳实践
✅ 做
- 选择解决实际问题的模式
- 保持模式简单易懂
- 文档记录为什么选择模式
- 考虑可测试性
- 遵循SOLID原则
- 使用依赖注入
- 优先组合而不是继承
❌ 不做
- 不理解模式就应用
- 过度设计简单解决方案
- 强迫模式适应不适用的地方
- 创建不必要的抽象层
- 忽视团队对模式的熟悉度
何时使用每种模式
| 模式 | 用例 |
|---|---|
| 单例 | 数据库连接,配置管理器 |
| 工厂 | 基于运行时条件创建对象 |
| 观察者 | 事件系统,发布/订阅,响应式编程 |
| 策略 | 可以在运行时更换的算法 |
| 装饰器 | 动态添加功能而不使用继承 |
| 仓库 | 从业务逻辑中抽象数据访问 |
| 适配器 | 使不兼容的接口协同工作 |
| 外观 | 简化复杂的子系统 |
| 命令 | 撤销/重做,任务队列,宏录制 |
资源
- 《设计模式》四人帮
- 《Head First设计模式》弗里曼和弗里曼
- refactoring.guru/design-patterns