何时使用构建者、工厂、适配器或策略:设计模式决策指南

原作者:Alina Kovtun

文章来自:When to Use Builder, Factory, Adapter, or Strategy: A Design Patterns Decision Guide | Women in Technology

摒弃死记硬背设计模式:用这套决策树精准选型

本文核心思路:基于业务痛点选型设计模式,适配所有面向对象语言,以最小的过度设计成本,落地最优代码解决方案。

设计模式的失效,极少是因为模式本身存在缺陷,更多是开发者在错误场景、基于错误诉求使用模式,或是用模式掩盖了真正的代码问题。多数时候,开发的难点不在于知晓策略模式(Strategy)这类技术范式,而在于判断当前业务是否真的需要它,或是是否存在更简洁的原生解决方案。

这正是决策树的核心价值:它让开发者在选型模式前建立标准化思考逻辑,精准定位代码中亟待解决的核心摩擦点。

你是否正面临对象创建逻辑日益复杂的问题?是否需要处理组件边界适配、外部依赖兼容场景?亦或是代码因业务行为迭代,不断堆砌条件判断语句?

本文提供一套标准化问题判定逻辑,帮助开发者快速筛选适配业务场景的设计模式。选型仍需结合业务判断力,但能大幅减少试错成本,让模式选型更高效、更精准。

设计模式的核心价值

设计模式的核心作用,是降低代码迭代与维护的重复成本,这也是其唯一有效的应用场景。

在工程实践中,这类高频冗余维护成本主要分为五类:

1. 业务变更联动性强,需批量修改大量文件,迭代效率低下;

2. 代码接口不规范、耦合严重,测试流程繁琐、用例脆弱,极易产生回归Bug;

3. 外部API侵入业务领域逻辑,代码充斥大量重复的接口适配、数据转换逻辑;

4. 构造函数与初始化逻辑持续膨胀,组件组合关系混乱,代码可读性极差;

5. 通用业务逻辑无统一承载载体,全局重复编写,代码冗余度极高。

切忌将设计模式视为代码“升级手段”。本质上,模式是在可控范围内换取代码灵活性的工程方案,而非全场景通用的优化工具,无需在所有代码模块中强行套用。

设计模式三问决策树

核心判定逻辑:先精准定位代码核心痛点,再逐层缩小选型范围,三大分支覆盖所有设计模式场景:

• 痛点源于对象创建 → 适配创建型模式

• 痛点源于对象结构与组件适配 → 适配结构型模式

• 痛点源于业务行为动态变更 → 适配行为型模式

无需固化记忆模式分类,重点聚焦业务痛点与问题本质,即可快速匹配最优方案。

分支一:对象创建问题(创建型设计模式)

适用场景:对象创建逻辑臃肿混乱,典型问题:构造函数参数泛滥、对象配置逻辑重复、默认参数定义模糊、多场景实例化规则散落代码库,无法统一管控。

步骤1:业务是否需要全局唯一实例?

单例模式选型必须依托真实业务诉求,“方便调用”绝对不能作为选型依据。滥用单例会隐藏代码依赖关系,大幅提升单元测试难度。

✅ 合理使用场景:无状态、可全局安全共享的资源(只读配置快照、进程级日志工具封装类等)。

❌ 风险使用场景:对象存储可变状态、绑定请求上下文、需要测试重置状态的资源。

优化替代方案:如需精细化实例创建、依赖管理,依赖注入、轻量应用容器的工程落地性,远优于全局单例。

组件A、组件B共享同一个日志单例实例,实现全局统一日志输出。

步骤2:对象构造逻辑复杂、易误用?

当构造函数存在大量可选参数、对象配置组合逻辑复杂时,优先选用构建者模式(Builder)。其核心价值不在于链式调用的代码美观度,而是规范化对象创建流程、实现参数前置校验、规避非法实例创建,从根源减少误用问题。

代码优化前后对比

# 未使用构建者:参数冗长、可读性差、极易传参出错
request = Request.new(url, method, headers, body, timeout, retry_count, cache)
# 使用构建者:语义清晰、参数可控、支持参数前置校验
request = RequestBuilder.new.url("https://api.example.com").method(:post).headers(auth_headers).timeout(2).build

除此之外,构建者模式可快速封装通用预设配置(默认重试策略、基础请求参数等),规避调用方重复编写冗余配置代码,大幅简化调用逻辑。

步骤3:是否需要根据业务场景动态选择实现类?

当代码需要根据配置文件、文件类型、服务提供者、功能开关、运行环境等条件动态选择实例类时,需集中统一管理实例化逻辑,避免分支判断语句散落代码库。

✅ 工厂方法模式:适用于「基类定义统一业务契约,子类实现具体实例化逻辑」的场景。

✅ 抽象工厂模式:适用于「批量创建一组相互关联、相互匹配的对象」场景(如服务专属客户端、数据映射器、参数校验器组合套件)。

✅ 原型模式:适用于「对象初始化成本高、配置流程复杂」场景,通过克隆已配置完成的实例,替代重复初始化,提升性能与稳定性。

分支二:对象结构适配问题(结构型设计模式)

适用场景:代码功能正常但结构臃肿、耦合度高,典型问题:外部接口侵入业务逻辑、子系统调用流程繁琐、对象组合混乱、模块边界模糊。

步骤1:需要兼容不兼容的接口规范?

当内部业务代码的接口规范,与第三方依赖、外部服务的接口规范不匹配时,优先使用适配器模式。该模式可隔离外部服务的接口差异、字段命名与数据结构特性,保护业务领域逻辑不受外部依赖变更影响。

业务适配示例

# 业务系统统一调用规范
payment_processor.process(amount, card)

# 第三方支付服务商原生接口规范
provider.execute_payment(card_info, transaction_amount)
# 适配器统一适配逻辑
class ProviderAdapter
  def initialize(provider)
    @provider = provider
  end

  def process(amount, card)
    # 统一转换数据格式,适配第三方接口
    @provider.execute_payment(card.to_provider_format, amount)
  end
end

核心开发原则:适配器仅负责接口转换、数据格式适配,严禁嵌入业务规则。业务逻辑需独立拆分,保证模块边界清晰。

执行流程:客户端调用统一接口 → 适配器完成接口、数据格式转换 → 调用第三方SDK能力

步骤2:子系统调用流程复杂、易出错?

当第三方库、内部子系统需要多步骤有序调用才能正常使用时,选用外观模式。该模式可封装底层复杂的调用逻辑与执行顺序,对外提供简洁统一入口,降低使用门槛,规避调用顺序错误、参数遗漏等问题。

场景示例:视频转换业务包含资源探测、转码处理、元数据提取、文件上传、资源清理等多步骤流程,外观模式可封装统一执行入口,内部自主编排逻辑,对外屏蔽复杂细节。

步骤3:需要叠加可选功能,避免子类爆炸?

当需要为核心功能叠加拓展能力(日志记录、数据加密、内容压缩、缓存处理等)时,传统子类继承会引发子类泛滥、代码冗余问题。装饰器模式可实现分层、显性、灵活的功能组合,无需定义大量子类。

最佳实践:每层装饰逻辑单一、职责独立、效果可预测;避免多层装饰逻辑相互依赖,防止调用链路混乱、副作用不可控。

步骤4:需要对对象做增强代理?

无需修改原有对象核心逻辑,即可实现懒加载、缓存复用、权限控制、接口监控、远程调用封装等增强能力时,优先使用代理模式,通过统一代理入口实现能力拓展。

步骤5:存在层级树形结构,需统一处理?

业务领域存在天然层级树形结构(文件系统、嵌套UI组件、分类菜单等),且需要统一处理叶子节点与容器节点逻辑时,适配组合模式,大幅简化层级结构的统一操作逻辑。

步骤6:大量共享对象存在内存冗余?

系统存在大量重复对象、对象静态数据占比高、重复创建成本高时,使用享元模式复用共享数据,减少内存占用。该模式在常规Web业务中应用较少,多用于编辑器、图形渲染、大型内存数据模型场景。

步骤7:需要解耦抽象与实现,支持双向扩展?

业务存在两个独立变化维度(如导出格式/导出设备、硬件设备/控制指令),为规避多层继承导致的子类矩阵爆炸问题,使用桥接模式,实现抽象层与实现层的独立迭代、双向拓展。

分支三:业务行为迭代问题(行为型设计模式)

适用场景:核心痛点为业务规则、工作流逻辑频繁变更,典型问题:方法堆砌大量if/else分支、算法策略随业务迭代频繁调整、流程拓展困难。

步骤1:请求需要多步骤链式处理?

适用于中间件式流水线处理场景:请求依次经过多节点校验、处理,单节点可终止流程或向下传递,优先选用责任链模式。

简易代码示例

class Handler
  def initialize(next_handler = nil)
    @next = next_handler
  end

  def call(request)
    return unless handle?(request)
    @next&.call(request)
  end
end

最佳实践:各处理节点职责单一、流程终止与传递规则清晰;禁止节点间相互依赖、擅自修改共享状态,避免流程失控。

步骤2:需要实现操作队列、重试、撤销、日志审计?

需要将业务操作封装为独立对象,实现任务排队、失败重试、操作审计、延迟执行、撤销回滚等能力时,选用命令模式,彻底解耦操作行为与调用方。

步骤3:需要动态替换算法策略,不改动调用逻辑?

同一业务存在多种可替换算法实现,需保证调用方逻辑稳定、无感知切换策略时,策略模式为最优解。高频场景:多渠道支付、路由决策、内容推荐、限流算法、数据格式化等。

选型特征:代码频繁出现「按业务类型匹配逻辑」的分支判断,且不同策略的测试逻辑高度重复、冗余严重。

步骤4:业务行为由状态驱动、规则复杂?

针对存在明确状态流转、节点转换规则的业务(流程审批、会话生命周期、设备连接状态等),使用状态模式。通过显性定义各状态专属行为,替代臃肿的条件分支,简化复杂状态逻辑。

步骤5:需要一对多订阅通知能力?

实现事件订阅、一对多消息发布通知场景时,选用观察者模式,可简洁落地领域事件推送能力。注意规避风险:严控观察者副作用,避免隐式联动导致流程不可控、逻辑混乱。

步骤6:需要数据快照与回滚撤销能力?

需要实现操作撤销、数据快照、状态回滚功能,且需屏蔽对象内部实现细节时,使用备忘录模式,安全保存、恢复对象历史状态。

步骤7:多对象复杂协调,需解耦依赖?

多业务对象存在复杂联动、直接依赖导致高耦合时,用中介者模式统一调度,消除对象直接依赖。多用于UI交互、复杂工作流编排场景。需严控中介者职责,避免逻辑过度集中导致组件臃肿。

步骤8:结构稳定,需持续新增操作能力?

业务数据结构长期稳定(如抽象语法树AST),需在不修改原有结构的前提下持续新增业务操作能力时,选用访问者模式。通用业务场景应用较少,特定领域可大幅提升代码拓展性。

决策树实战落地:常见业务场景选型

场景1:多渠道消息推送(邮件、短信、推送通知)

随着推送渠道增多、发送规则迭代,传统分支代码会持续臃肿。引入策略模式,定义统一消息发送接口,各渠道独立实现发送逻辑,通过配置/功能开关动态匹配策略。新增渠道无需修改核心调用代码,拓展性极强。

核心实现方案:定义统一接口 NotificationChannel#send(user, message),各渠道独立实现接口逻辑,通过策略选择器动态匹配执行。

场景2:API请求链路处理(限流 → 认证 → 业务处理)

API请求需按固定顺序完成限流、认证、业务处理等多重校验流程,适配责任链模式。各处理节点职责单一、独立可测试,支持灵活调整节点顺序、增删处理步骤,不影响核心链路,安全性与可维护性极高。

场景3:多样化报表生成(多配置、多格式导出)

报表生成参数繁杂、配置组合多样,适配构建者模式规范化参数配置、规避无效配置、简化复杂组合逻辑;同时搭配策略模式,适配PDF、CSV、XLSX等多格式导出,无需嵌套条件判断语句。


何时使用构建者、工厂、适配器或策略:设计模式决策指南
https://blog.cikaros.cn/archives/he-shi-shi-yong-gou-jian-zhe-gong-han-gua-pei-qi-huo-ce-lue-she-ji-mo-shi-jue-ce-zhi-nan
作者
Cikaros
发布于
2026年06月16日
许可协议