1. 设计模式入门:为什么我们需要模式?
2004年我第一次在项目中尝试使用Singleton模式时,团队里有个老工程师对我说:"模式不是银弹,但不懂模式就像厨子不认识调料。"这句话让我记到现在。设计模式本质上就是前辈们总结出来的最佳实践套路,就像做菜的"红烧""清蒸"这类固定技法。
在面向对象开发中,我们经常会遇到一些反复出现的设计问题。比如:
- 需要确保一个类只有一个实例(Singleton)
- 想要灵活地创建对象而不暴露创建逻辑(Factory)
- 需要在不同对象间建立松耦合的通信机制(Observer)
23种经典设计模式就是针对这类问题的标准化解决方案。它们最早由GoF(Gang of Four)在《设计模式:可复用面向对象软件的基础》一书中系统归纳,成为每个程序员进阶的必修课。
重要提示:设计模式不是语法特性,而是设计思路。就像同样的食材可以用不同烹饪方法,同一个功能也可以用不同模式实现。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 设计模式三大类型解析
2.1 创建型模式(5种)
这些模式关注对象创建的灵活性。想象你开了一家披萨店:
-
工厂方法(Factory Method)
定义创建对象的接口,让子类决定实例化哪个类。就像:java复制interface PizzaFactory { Pizza createPizza(); } class NYPizzaFactory implements PizzaFactory { public Pizza createPizza() { return new NYStylePizza(); } } -
抽象工厂(Abstract Factory)
创建相关或依赖对象的家族,而不指定具体类。比如:python复制class GUIFactory: def create_button(self): pass def create_checkbox(self): pass class WinFactory(GUIFactory): def create_button(self): return WinButton() -
建造者(Builder)
分步骤构建复杂对象。就像点餐时的定制流程:javascript复制const pizza = new PizzaBuilder() .setSize('large') .addTopping('mushroom') .build(); -
原型(Prototype)
通过复制现有对象来创建新对象。JS中的Object.create()就是典型应用。 -
单例(Singleton)
确保一个类只有一个实例。常用在数据库连接、配置管理等场景:csharp复制public sealed class Singleton { private static Singleton _instance; private Singleton() {} public static Singleton GetInstance() { return _instance ??= new Singleton(); } }
2.2 结构型模式(7种)
处理类或对象的组合方式:
-
适配器(Adapter)
让不兼容的接口协同工作。就像Type-C转USB转换头:java复制class MicroUSBToTypeCAdapter implements TypeC { private MicroUSB microUSB; public void charge() { microUSB.slowCharge(); } } -
桥接(Bridge)
将抽象与实现分离。比如不同品牌的电视和遥控器:python复制class RemoteControl: def __init__(self, device): self.device = device def toggle_power(self): self.device.power = not self.device.power -
组合(Composite)
用树形结构处理部分-整体关系。文件系统就是典型例子:javascript复制class File { constructor(name) { this.name = name; } } class Folder { constructor(name) { this.name = name; this.children = []; } add(child) { this.children.push(child); } } -
装饰器(Decorator)
动态添加职责。就像给咖啡加配料:typescript复制interface Coffee { cost(): number; } class MilkDecorator implements Coffee { constructor(private coffee: Coffee) {} cost() { return this.coffee.cost() + 2; } } -
外观(Facade)
提供简化接口。就像一键启动电脑:csharp复制class Computer { public void Start() { cpu.Start(); memory.Check(); disk.Boot(); } } -
享元(Flyweight)
共享细粒度对象。游戏中重复使用的树木贴图就是典型应用。 -
代理(Proxy)
控制对象访问。比如图片懒加载:python复制class ImageProxy: def __init__(self, filename): self.filename = filename self._image = None def display(self): if not self._image: self._image = RealImage(self.filename) self._image.display()
2.3 行为型模式(11种)
关注对象间的通信和职责分配:
-
责任链(Chain of Responsibility)
让多个对象有机会处理请求。就像审批流程:javascript复制class Approver { setNext(approver) { this.next = approver; } process(request) { if (canHandle(request)) handle(request); else if (this.next) this.next.process(request); } } -
命令(Command)
将请求封装为对象。实现撤销/重做功能:java复制interface Command { void execute(); void undo(); } class CopyCommand implements Command { public void execute() { editor.copy(); } public void undo() { editor.removeClipboard(); } } -
解释器(Interpreter)
定义语言的文法表示。SQL解析就是典型应用场景。 -
迭代器(Iterator)
提供顺序访问集合元素的方法。各种语言的for...of背后都是这个模式。 -
中介者(Mediator)
通过中介对象封装交互。聊天室就是典型案例:python复制class ChatRoom: def show_message(self, user, message): print(f"[{user.name}]: {message}") -
备忘录(Memento)
捕获并外部化对象状态。游戏存档功能:csharp复制class GameMemento { public int Level { get; } public int Score { get; } public GameMemento(int level, int score) { Level = level; Score = score; } } -
观察者(Observer)
定义对象间的一对多依赖。事件监听:javascript复制class Subject { constructor() { this.observers = []; } subscribe(observer) { this.observers.push(observer); } notify(data) { this.observers.forEach(o => o.update(data)); } } -
状态(State)
允许对象在内部状态改变时改变行为。比如订单状态:java复制interface OrderState { void next(Order order); } class ProcessingState implements OrderState { public void next(Order order) { order.setState(new ShippedState()); } } -
策略(Strategy)
定义算法家族,使它们可以互相替换。支付方式选择:python复制class PaymentContext: def __init__(self, strategy): self.strategy = strategy def execute_payment(self, amount): return self.strategy.pay(amount) -
模板方法(Template Method)
定义算法骨架,子类实现某些步骤。就像冲泡饮料:typescript复制abstract class Beverage { prepareRecipe() { this.boilWater(); this.brew(); this.pourInCup(); this.addCondiments(); } abstract brew(): void; abstract addCondiments(): void; } -
访问者(Visitor)
在不修改类的前提下定义新操作。适用于复杂对象结构:csharp复制interface IVisitor { void Visit(ElementA element); void Visit(ElementB element); } class ConcreteVisitor : IVisitor { public void Visit(ElementA element) { Console.WriteLine("Processing ElementA"); } }
3. 模式选择实战指南
3.1 何时使用何种模式?
根据问题特征选择模式:
| 问题场景 | 适用模式 |
|---|---|
| 需要控制实例数量 | Singleton |
| 创建逻辑复杂 | Factory Method/Abstract Factory |
| 需要动态添加功能 | Decorator |
| 不同对象需要联动 | Observer/Mediator |
| 需要保存和恢复状态 | Memento |
| 算法需要灵活切换 | Strategy |
3.2 模式组合的经典案例
实际项目中经常组合使用多个模式:
-
MVC架构
- Observer:模型变更通知视图
- Strategy:控制器使用不同策略处理请求
- Composite:视图的嵌套结构
-
游戏开发
- State:角色状态切换
- Command:操作指令封装
- Flyweight:共享粒子效果
3.3 常见误区和注意事项
-
不要过度设计
简单的if-else能解决的问题,没必要强行套用模式。我曾见过用Visitor模式处理两个简单类,结果代码量翻了三倍。 -
理解本质而非死记硬背
模式的关键在于思想。比如你不一定要严格按GoF的方式实现Observer,现代语言中的事件机制就是它的变体。 -
注意语言特性
很多模式在动态语言中可以简化。比如Python的装饰器语法@decorator就比Java的实现简洁得多。 -
性能考量
某些模式会增加间接层(如Proxy),在高性能场景需要权衡。
4. 现代编程中的模式演进
随着编程范式的发展,模式也在进化:
-
函数式编程的影响
- Strategy模式可以简化为高阶函数:
javascript复制const pay = (strategy) => (amount) => strategy(amount); const creditCardPay = pay(amount => console.log(`Paid ${amount} via CC`));
- Strategy模式可以简化为高阶函数:
-
响应式编程
Observer模式在RxJS等库中被发扬光大:typescript复制const observable = new Observable(subscriber => { subscriber.next(1); }); observable.subscribe(console.log); -
微服务架构
- API Gateway是Facade模式的分布式实现
- Circuit Breaker是State模式的应用
-
前端框架
- React Hooks可以看作Strategy和Observer的组合
- Vue的provide/inject实现了依赖注入
设计模式就像编程界的成语,用得好能让代码更优雅,但滥用反而会让代码难以理解。我的经验法则是:当发现自己在重复解决类似设计问题时,再考虑引入模式。记住,模式是工具,不是目标。
