如何选择设计模式:根据业务场景、变化点、复用性、可维护性进行综合评估
说实话,我见过太多人学设计模式时陷入一个怪圈——背了二十三种模式的类图,面试时对答如流,一到真实项目就懵了。为什么会这样?因为大家总在问「这个模式怎么用」,却很少问「我该不该用这个模式」。
今天我们就来聊聊这个核心问题。我个人习惯把选择设计模式比作「开药方」——你得先诊断病情,再对症下药。盲目套用模式,就像不管什么病都开阿莫西林,后果可想而知。
核心观点:设计模式的选择不是一道选择题,而是一道综合评估题。你需要从业务场景、变化点、复用性、可维护性四个维度去权衡。
一、先看业务场景:模式不是万能的
我在项目中遇到过这样一个场景:一个电商系统的订单处理流程,需要支持多种支付方式。当时团队里有人直接说「用策略模式啊」,然后就开干了。结果做到一半发现,支付方式之间其实有共享的逻辑(比如日志记录、异常处理),策略模式反而让代码变得支离破碎。
你看,这就是典型的「拿着锤子看什么都像钉子」。选择模式的第一步,不是翻书找模式,而是把业务场景拆清楚:
- 这个场景的核心职责是什么?——是创建对象?是组织算法?还是协调多个对象?
- 场景中有没有明显的「变」与「不变」?——变化点往往就是模式的切入点
- 这个场景的生命周期有多长?——临时需求别上大炮打蚊子
举个例子,如果你只是做一个简单的日志工具,用单例模式就够了。但如果你要做一个支持多种输出格式(JSON、XML、纯文本)的日志系统,那策略模式或装饰器模式才值得考虑。
我的经验:先画一个简单的业务流程图,把「变」的部分圈出来。如果变化点超过3个,再考虑用模式;如果只有1个变化点,一个if-else可能更清晰。
二、识别变化点:模式是为「变化」服务的
设计模式的本质,说白了就是「封装变化」。你想想看,GoF的二十三种模式,哪一个不是在解决「某部分容易变化」的问题?
我习惯把变化点分为三类:
| 变化类型 | 典型场景 | 推荐模式 |
|---|---|---|
| 算法/行为变化 | 支付方式、排序算法、促销策略 | 策略模式、模板方法模式 |
| 对象创建变化 | 不同数据库连接、不同UI组件 | 工厂模式、建造者模式 |
| 对象交互变化 | 事件通知、消息推送、状态流转 | 观察者模式、状态模式 |
这里有个坑,我曾经踩过——过度封装变化。有一次我接手一个报表系统,发现里面用了三层抽象工厂,就为了支持两种数据库。结果代码读起来像俄罗斯套娃,改一个字段要动四个文件。嗯,后来我重构时发现,其实用简单的工厂方法加配置就能搞定。
避坑指南:我曾经因为过度设计,把一个只需要支持MySQL的系统硬生生做成了「支持所有数据库」的架构。结果项目交付后两年,其他数据库一个都没用上。记住:只为当前已知的变化做设计,不要为想象中的变化买单。
三、评估复用性:别为了复用而复用
复用性是个好东西,但也是个陷阱。我见过太多人为了「复用」而引入设计模式,结果代码的耦合度反而更高了。
怎么评估复用性?我一般问自己三个问题:
- 这段代码会被几个地方调用?——如果只有一处调用,别急着抽象
- 调用方对这段代码的期望是否一致?——如果每个调用方都想要不同的行为,强行复用反而坏事
- 复用的代价是什么?——引入接口、抽象类、工厂,这些都会增加理解成本
举个例子,你写了一个数据导出功能,目前只支持导出Excel。如果未来大概率要支持PDF和CSV,那用策略模式封装导出算法是合理的。但如果这个导出功能只有这一个场景在用,而且未来半年都没有扩展计划,那一个简单的方法就够了。
我的原则:复用性不是越高越好,而是「恰到好处」。我宁愿写两段相似的代码,也不愿引入一个让团队所有人都看不懂的抽象层。
四、权衡可维护性:模式是工具,不是目的
可维护性,说白了就是「未来的人改代码时会不会骂娘」。设计模式能提升可维护性,但前提是——团队里的人都懂这个模式。
我记得有一次做代码评审,看到有人用责任链模式处理一个只有三个步骤的校验流程。代码写得确实漂亮,每个处理器都遵循了单一职责。但问题是,团队里一半的人看不懂责任链模式,每次改需求都要拉着原作者问半天。你说这算可维护性好还是不好?
所以,评估可维护性时,我建议考虑以下几点:
- 团队的技术水平——如果团队普遍对设计模式不熟,优先选择简单直观的模式(如策略模式、工厂方法),少用复杂的模式(如访问者模式、解释器模式)
- 代码的可读性——模式引入后,代码是变清晰了还是变绕了?如果绕了,说明选错了
- 修改的便利性——当需求变化时,改一处代码就能搞定,还是需要改多处?
一个小技巧:写完代码后,假装自己是三个月后的自己,重新读一遍。如果读不懂,说明可维护性有问题。
五、综合评估框架:一张图说清楚
说了这么多,我们来总结一下。我平时做模式选择时,会画这样一张决策图:
这张图的核心逻辑是:从业务需求出发,依次评估四个维度。每个维度都有对应的子问题,回答完这些问题后,你自然就知道该用哪个模式了。
六、实战案例:一个订单系统的模式选择
最后,我们来看一个完整的案例。假设你要设计一个订单系统,支持以下功能:
- 普通订单、团购订单、秒杀订单三种类型
- 每种订单的创建流程不同,但都有校验、计算价格、生成订单三个步骤
- 未来可能增加新的订单类型(如拼团订单)
我们按四个维度来评估:
| 评估维度 | 分析结果 | 模式建议 |
|---|---|---|
| 业务场景 | 核心是「订单创建」,不同订单类型有共同步骤也有差异 | 模板方法模式(固定步骤)+ 策略模式(差异部分) |
| 变化点 | 订单类型会新增,但创建流程的骨架不变 | 模板方法模式封装骨架,子类实现差异 |
| 复用性 | 校验、价格计算等逻辑会被多个订单类型复用 | 策略模式封装可复用的算法 |
| 可维护性 | 团队熟悉模板方法和策略模式,代码结构清晰 | 两种模式结合,新增订单类型只需新增子类 |
最终,我选择了模板方法模式 + 策略模式的组合。模板方法定义订单创建的骨架,策略模式处理价格计算等可变算法。这样既保证了复用性,又让新增订单类型变得非常简单。
总结一下:选择设计模式没有标准答案,但有标准方法。从业务场景出发,识别变化点,评估复用性,权衡可维护性——把这四步走完,你的选择就不会太离谱。
记住,设计模式是工具,不是目的。用对了,代码如诗;用错了,代码如屎。嗯,这话糙理不糙。