1. 设计模式:程序员的内功心法
第一次接触设计模式是在2013年,当时接手一个遗留系统重构项目。面对错综复杂的业务逻辑和随意堆砌的代码,我花了整整两周时间才理清各个模块的关系。直到一位资深工程师指着屏幕说:"这里明显该用策略模式,那边应该用观察者模式...",我才恍然大悟——原来优秀的代码是有章法的。
设计模式不是银弹,但确实是程序员的内功心法。就像武侠小说中的招式套路,23种经典设计模式(GoF模式)是前辈们总结出的最佳实践。它们解决了面向对象设计中反复出现的特定问题,比如:
- 对象创建(工厂模式、建造者模式)
- 结构组织(适配器模式、装饰器模式)
- 行为管理(观察者模式、状态模式)
重要提示:设计模式不是用来炫技的。我曾见过为了用模式而用模式的代码,把简单的需求复杂化。正确的做法是:先理解问题本质,当发现"这个场景似曾相识"时,再选用合适的模式。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 设计模式的三大类型与典型场景
2.1 创建型模式:解耦对象的创建过程
在电商系统开发中,我遇到过这样的需求:根据用户等级创建不同优惠策略。如果直接new对象,代码会充满if-else:
java复制if(user.isVIP()) {
strategy = new VIPDiscountStrategy();
} else if(user.isSVIP()) {
strategy = new SVIPDiscountStrategy();
}
// 更多判断...
改用工厂方法模式后:
java复制public interface DiscountStrategyFactory {
DiscountStrategy create(User user);
}
// 调用处
strategy = factory.create(currentUser);
这个案例体现了创建型模式的核心价值:
- 将对象创建与使用分离
- 支持扩展(新增策略类型不影响现有代码)
- 统一创建入口,便于维护
其他常用创建型模式:
- 抽象工厂:需要创建产品族时(如跨平台UI组件)
- 建造者:构造复杂对象(如包含多种可选配置的订单)
- 原型:克隆成本高的对象(如游戏中的NPC)
2.2 结构型模式:构建灵活的对象结构
去年优化一个物联网项目时,设备上报的数据格式五花八门。我们使用适配器模式统一处理:
python复制class DeviceAdapter:
def get_unified_data(self):
# 将不同设备数据转换为统一格式
pass
# 具体适配器
class HuaweiAdapter(DeviceAdapter):
def __init__(self, huawei_device):
self.device = huawei_device
def get_unified_data(self):
return {
"temp": self.device.getTemperature() / 10,
"humidity": self.device.readHumidity()
}
结构型模式就像乐高积木的连接件:
- 适配器:接口转换(旧系统整合常用)
- 装饰器:动态添加功能(Java I/O流经典实现)
- 代理:控制访问(Spring AOP底层机制)
- 组合:树形结构处理(组织架构、菜单权限)
2.3 行为型模式:优雅的对象协作方式
在开发消息通知系统时,观察者模式派上大用场:
typescript复制// 主题接口
interface Subject {
attach(observer: Observer): void;
notify(): void;
}
// 具体主题
class OrderSubject implements Subject {
private observers: Observer[] = [];
public attach(observer: Observer) {
this.observers.push(observer);
}
public orderCompleted() {
this.notify();
}
private notify() {
this.observers.forEach(obs => obs.update(this));
}
}
// 观察者实现(邮件服务、短信服务等)
class EmailObserver implements Observer {
update(subject: Subject) {
sendOrderCompleteEmail();
}
}
行为型模式解决了对象间的通信问题:
- 观察者:事件驱动架构基础(如Redux)
- 策略:算法切换(支付方式选择)
- 状态:行为随状态改变(订单状态流转)
- 模板方法:固定算法骨架(JdbcTemplate)
3. 设计模式的实践智慧
3.1 何时该用设计模式?
根据我的经验,这些信号表明可能需要引入模式:
- 代码中出现重复的"套路"(如多处相似的创建逻辑)
- 修改一个功能会意外破坏其他功能(紧耦合)
- 添加新功能必须修改现有代码(违反开闭原则)
- 类职责不清晰(一个类做太多事)
但也要警惕过度设计。我遵循的原则是:
- 第一次遇到问题:直接解决
- 第二次遇到相似问题:考虑抽象
- 第三次遇到:应用设计模式
3.2 常见误用与规避方法
反例1:强迫症式应用模式
曾经见过有人把简单的数据查询改成抽象工厂+策略模式+装饰器的组合,导致10行能完成的功能变成10个类。正确做法是:当模式带来的复杂度 > 解决的问题时,应该放弃使用。
反例2:生搬硬套GoF模式
GoF模式基于90年代的C++/Smalltalk,现代语言已有更优雅的实现。比如:
- Java/Spring的依赖注入替代工厂模式
- Python装饰器语法替代装饰器模式
- Kotlin的委托替代代理模式
反例3:忽视语言特性
在JavaScript项目中强行实现经典的单例模式反而多余,直接用ES6模块的天然单例特性更简单:
javascript复制// 正确做法
export default new Logger();
// 过度设计
class SingletonLogger {
static getInstance() {
if(!this.instance) {
this.instance = new Logger();
}
return this.instance;
}
}
3.3 设计模式的演进趋势
随着编程范式的发展,新模式不断涌现:
- 反应式模式:响应式编程中的背压处理
- 云设计模式:断路器、事件溯源(微服务常用)
- 函数式模式:Monad、Functor(FP范畴论概念)
同时,传统模式也有新变化:
- 现代IDE的代码生成功能减少了模板代码
- 注解/装饰器语法简化了模式实现
- 组合优于继承成为新共识
4. 从理论到实践:模式学习路线
4.1 学习资源的甄别建议
看过20+本设计模式书籍后,我推荐:
- 初学者:《Head First设计模式》(图文并茂)
- 进阶者:《设计模式:可复用面向对象软件的基础》(原汁原味)
- 实践者:《实现模式》(Kent Beck的实用建议)
避免:
- 只讲UML不讲场景的书
- 用动物、车辆等脱离实际的例子
- 没有对比不同实现优劣的内容
4.2 我的刻意练习方法
-
模式识别训练:
- 阅读开源代码(如Spring、React)时标注使用的模式
- 每周重构一段旧代码,尝试用模式改进
-
场景映射练习:
markdown复制
| 业务场景 | 适用模式 | 理由 | |--------------------|------------------------|--------------------------| | 支付方式切换 | 策略模式 | 算法可互换 | | 订单状态流转 | 状态模式 | 行为随状态改变 | | 跨平台UI组件库 | 抽象工厂 | 需要创建产品族 | -
反模式案例收集:
建立自己的代码片段库,记录:- 坏味道代码(如上帝对象)
- 重构前后对比
- 不同模式的性能影响
4.3 面试中的设计模式
作为技术面试官,我常通过这些问题考察候选人:
-
"请比较策略模式和状态模式的异同"
- 期望听到:状态模式中状态知道其他状态,策略模式中各策略独立
-
"如果要用模式优化这段代码,你会选哪种?为什么?"
- 考察点:模式选择依据而非模式名称
-
"你最近在什么项目中用了什么模式?解决了什么问题?"
- 警惕:回答所有项目都用过所有模式的候选人
设计模式不是用来背诵的,就像武术套路要在实战中掌握。建议从自己负责的模块开始,每次迭代尝试应用一个新模式,持续反思改进。我个人的经验是:真正掌握一个模式,需要至少三次成功的实践和一次失败的教训。
