1. 设计模式入门:为什么我们需要模式?
刚入行写代码那会儿,我经常遇到这种情况:好不容易实现了个功能,过两周再看代码却像在读天书。更糟的是,当类似需求换个马甲又出现时,还得重新造轮子。直到接触了设计模式,才发现原来早有前辈把这类问题的优雅解法总结成了"套路"。
设计模式不是语法也不是框架,而是面向对象设计中反复出现的各类问题的经典解决方案。就像建筑领域的标准结构(比如拱桥、悬索桥),程序员面对特定场景时可以直接套用这些经过验证的设计模板。Gang of Four(GoF)在1994年出版的《设计模式》中归纳了23种基础模式,至今仍是开发者的必修课。
重要提示:设计模式不是银弹,滥用模式比不用更危险。合适的模式用在合适的场景才能发挥价值。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 模式分类与核心思想
2.1 三大类型速览
所有模式按目的分为三类,用建筑来类比理解:
-
创建型(5种):解决对象创建问题
相当于建筑中的"建材生产"——是用工厂流水线(工厂方法)还是按需定制(建造者)? -
结构型(7种):处理对象组合方式
类似建筑中的"结构设计"——要不要加个中转层(代理)?如何实现灵活的扩展(装饰器)? -
行为型(11种):定义对象间交互
好比建筑中的"使用规范"——怎么通知各房间火灾警报(观察者)?电梯如何响应不同楼层请求(责任链)?
2.2 模式学习的黄金法则
我总结的实践心得:
- 先理解场景痛点,再学模式解法
- 从简单实现开始,逐步引入模式
- 画UML图比死记硬背更有用
- 多思考"如果不用模式会怎样"
3. 创建型模式实战图解
3.1 单例模式:全局唯一实例
场景:配置文件读取、线程池、数据库连接池等需要严格控制实例数量的情况。
java复制// 双重检查锁定实现
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
避坑指南:
- 注意多线程环境下的可见性问题(volatile关键字)
- 反射攻击会破坏单例,需要防御性编程
- 考虑序列化时的实例控制
3.2 工厂方法:灵活的对象工厂
经典案例:日志记录器需要支持文件/数据库/网络等多种输出方式。
python复制from abc import ABC, abstractmethod
class Logger(ABC):
@abstractmethod
def log(self, message: str):
pass
class FileLogger(Logger):
def log(self, message):
print(f"Writing to file: {message}")
class DatabaseLogger(Logger):
def log(self, message):
print(f"Storing to DB: {message}")
class LoggerFactory:
def get_logger(self) -> Logger:
if config.log_type == "file":
return FileLogger()
else:
return DatabaseLogger()
模式对比:
| 模式 | 适用场景 | 复杂度 |
|---|---|---|
| 简单工厂 | 产品类型固定且较少 | ★★☆ |
| 工厂方法 | 需要扩展新产品类型 | ★★★ |
| 抽象工厂 | 需要创建产品家族 | ★★★★ |
4. 结构型模式应用解析
4.1 适配器模式:兼容接口转换
现实类比:Type-C转3.5mm耳机接口的转接头
typescript复制// 现有接口
interface MicroUSB {
charge(): void;
}
// 目标接口
interface USB_C {
fastCharge(): void;
}
// 适配器实现
class USB_C_Adapter implements USB_C {
private microUSB: MicroUSB;
constructor(device: MicroUSB) {
this.microUSB = device;
}
fastCharge() {
console.log("Converting to MicroUSB...");
this.microUSB.charge();
}
}
适用场景:
- 整合遗留系统代码
- 对接第三方库接口
- 统一不同版本的API
4.2 装饰器模式:动态添加功能
咖啡加料案例:
javascript复制class Coffee {
cost() { return 5; }
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1;
}
}
// 使用
let myCoffee = new Coffee();
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);
console.log(myCoffee.cost()); // 输出8
优势:
- 比继承更灵活
- 避免子类爆炸
- 运行时动态组合
5. 行为型模式深度剖析
5.1 观察者模式:事件通知机制
实际应用:电商系统中的库存预警
java复制// 主题接口
interface StockSubject {
void register(Observer o);
void notifyObservers();
}
// 具体主题
class Inventory implements StockSubject {
private List<Observer> observers = new ArrayList<>();
private int stock;
public void setStock(int stock) {
this.stock = stock;
if(stock < 10) {
notifyObservers();
}
}
@Override
public void register(Observer o) {
observers.add(o);
}
@Override
public void notifyObservers() {
for(Observer o : observers) {
o.update(stock);
}
}
}
// 观察者实现
class AlertSystem implements Observer {
@Override
public void update(int stock) {
System.out.println("警报:当前库存仅剩" + stock);
}
}
实现变体:
- 推模型(主动推送数据)
- 拉模型(观察者自行获取数据)
- 使用Java内置Observable类
5.2 策略模式:算法自由切换
支付方式案例:
python复制from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float) -> bool:
pass
class CreditCardPayment(PaymentStrategy):
def pay(self, amount):
print(f"Processing ${amount} via Credit Card")
return True
class PayPalPayment(PaymentStrategy):
def pay(self, amount):
print(f"Processing ${amount} via PayPal")
return True
class ShoppingCart:
def __init__(self):
self._strategy = None
def set_payment(self, strategy: PaymentStrategy):
self._strategy = strategy
def checkout(self, amount):
if self._strategy:
return self._strategy.pay(amount)
raise Exception("Payment method not set")
模式对比表:
| 模式 | 关注点 | 灵活性 |
|---|---|---|
| 策略模式 | 算法替换 | 运行时切换 |
| 模板方法 | 算法步骤 | 编译期确定 |
| 命令模式 | 请求封装 | 更高抽象层 |
6. 模式选择与组合实践
6.1 典型组合案例
MVC架构中的模式混用:
- 观察者模式(Model通知View更新)
- 策略模式(Controller可替换)
- 组合模式(UI组件树)
- 工厂方法(创建View组件)
6.2 反模式警示
我在项目中见过的典型误用:
- 为单例而单例,导致测试困难
- 过度使用装饰器造成调用链过长
- 观察者注册后未注销引发内存泄漏
- 策略模式类爆炸(可用lambda优化)
7. 现代语言中的模式演进
7.1 Java Stream中的模式
java复制List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 责任链+装饰器
names.stream()
.filter(name -> name.length() > 3) // 策略
.map(String::toUpperCase) // 装饰
.forEach(System.out::println); // 观察者
7.2 JavaScript高阶函数实现
javascript复制// 工厂方法
const loggerFactory = (type) => {
if(type === 'file') return msg => console.log(`[FILE] ${msg}`);
return msg => console.log(`[CONSOLE] ${msg}`);
}
// 观察者简化版
const createObservable = () => {
let listeners = [];
return {
subscribe: fn => listeners.push(fn),
notify: data => listeners.forEach(fn => fn(data))
};
};
8. 学习路线与资源推荐
8.1 渐进式学习路径
-
初级阶段(1-2周):
- 掌握单例、工厂方法、观察者、策略
- 实现简单案例(如日志系统、支付模块)
-
中级阶段(3-4周):
- 理解装饰器、适配器、代理
- 研究Spring等框架中的模式应用
-
高级阶段(持续实践):
- 分析模式组合场景
- 学习响应式编程中的模式变体
8.2 经典学习资料
- 图书:《Head First设计模式》(图文并茂)
- 网站:Refactoring.Guru(交互式图解)
- 开源项目:Spring框架源码(模式实战典范)
- 工具:PlantUML(绘制模式类图)
9. 真实项目中的模式思考
去年重构一个老旧系统时,我们用了这些模式:
- 用适配器整合遗留的XML接口
- 用策略模式实现多供应商的计价规则
- 用观察者实现审计日志功能
关键收获:
- 模式引入要评估维护成本
- 文档比精巧的设计更重要
- 团队共识决定模式实施成败
设计模式就像武术套路,真正实战时需要灵活组合。建议从简单的模式开始,先写出"能用"的代码,再逐步重构为"好用"的设计。记住:代码首先是给人读的,其次才是给机器执行的。
