从变更方向识别结构——设计模式的选型逻辑

设计模式不是按分类背的,是按变更方向选的——看懂代码未来往哪里变,模式自然浮现

本页目录

设计模式不是编程技巧的集合,是代码结构决策的词汇表。GoF 把 23 个模式分成创建型、结构型、行为型,这个分类便于记忆但不便于选用。实际使用时更有效的分类维度是:你的代码未来最可能沿哪个方向变化。

变更方向决定模式选择

代码的变化不是随机的。多数系统的变化集中在几个方向上:增加行为变体、叠加功能层、替换创建方式、调整模块交互。

每个变更方向对应一组模式。识别方向比记住模式名更重要,因为方向确定了,候选模式通常不超过两三个。

行为变体增加——同一个操作有多种不同的做法,而且做法还会继续增加。Strategy 把行为从控制流中抽出来变成可替换的对象;State 在此基础上增加了状态转移的约束。

功能动态叠加——核心能力不变,但需要在外面包不同的附加功能,而且包的方式在运行时才确定。Decorator 让每一层附加功能独立存在,可以任意组合和排序。

创建逻辑复杂化——对象的构建过程变复杂了,或者不同环境需要创建不同的产品族。Factory Method 处理单一产品的创建变体;Abstract Factory 处理产品族;Builder 处理多步骤构建。

模块交互膨胀——模块之间的直接调用越来越多,改一个接口牵动一串。Mediator 收拢调用关系;Observer 解耦事件的发送方和接收方。

抽象层级的平衡点

引入模式就是增加抽象层。每增加一层,灵活性提升但可读性下降。

判断平衡点的经验法则:抽象层数不应超过具体变体数。两种支付方式不需要三层工厂结构;三种日志格式不需要 Abstract Factory。

另一个判断维度是团队的理解成本。如果引入一个模式之后,团队里只有两个人能看懂代码,这个模式的实际价值是负的——它把风险从代码结构转移到了人员依赖上。

好的抽象让代码的读者不需要看实现就能理解意图。如果引入模式之后,理解代码反而需要跳更多层,说明抽象层级过了。

组合优于继承——一条贯穿全书的设计原则

23 个模式中,绝大多数都偏向组合而不是继承。原因不是继承不好,而是继承关系一旦建立就很难改变。

继承是编译时绑定。父类和子类之间的关系写死在代码里,运行时不能换。组合是运行时绑定。对象之间通过接口合作,换一个实现只需要换一个注入。

实际工程中,继承层级超过两层就要警惕。超过三层的继承链通常意味着有些职责应该被抽出来变成组合关系。

这条原则在 Decorator(用组合叠加功能替代继承扩展)、Strategy(用组合替换行为替代子类覆写)、Bridge(把抽象和实现分成两个独立的继承体系,通过组合连接)中反复出现。

模式之间的协作与冲突

实际项目中很少只用一个模式。常见的协作组合:

Factory + Strategy:工厂负责创建不同的策略对象,调用方不关心策略的具体类型。这组搭配让行为的选择和行为的创建都解耦了。

Observer + Mediator:Observer 处理事件通知,Mediator 收拢模块间的复杂交互。事件少的时候用 Observer 就够了;事件多且存在复杂的条件触发时,Mediator 更合适。

Decorator + Template Method:Template Method 定义算法骨架,Decorator 给骨架的输入输出包装附加功能。骨架不变,但进出的数据可以被灵活处理。

冲突的组合也存在。Strategy 和 Template Method 解决的问题有重叠——都是"同一个流程的某些步骤可替换"。Strategy 通过组合替换整个行为对象;Template Method 通过继承覆写个别步骤。同一个位置不要两个都用。

同分类继续看