有哪些常见设计模式,优缺点、适用场景和项目使用情况如何?
未标记
询问 AI
考查重点:变化隔离与抽象成本。按创建/结构/行为归类,选策略或适配器举真实变化点,比较扩展收益与额外抽象成本
本题目录
参考答案
核心回答
设计模式是解决常见代码组织问题的经验,核心是把容易变化的部分隔离起来,让依赖关系和扩展位置清楚。常见模式可以按创建对象、组合对象、组织行为分为创建型、结构型和行为型。
比较常用的几种如下:
- 工厂方法:通过创建接口和具体创建者,隔离对象构造与使用方,适合需要扩展产品类型、构造过程有差异的场景。优点是调用方少依赖具体类;代价是创建者和产品类型可能增加。简单工厂、注册表也是常见创建方案,但结构不完全等同于工厂方法。
- 策略:把同一任务的不同算法或规则封装成可替换实现,例如不同用户的优惠计算。优点是变化相互隔离、便于单独测试;代价是需要明确策略选择规则,类型过多时也会增加管理成本。
- 适配器:把外部接口转换成业务需要的接口,例如统一不同供应商的参数、错误码和返回值。优点是隔离外部差异;代价是多一层转换,还必须处理两边语义并不完全一致的问题。
- 装饰器:在保持调用接口的基础上,通过包装对象组合附加能力,例如给同一发送能力叠加日志或指标。优点是能力可组合;代价是包装顺序、异常传播和多层调用更难追踪。
- 单例:控制实例数量并提供统一访问入口,适合确实需要共享的一份资源管理对象。优点是避免重复创建;代价是全局依赖、测试隔离和共享可变状态问题,单例本身不保证线程安全。
选择时要同时说明收益和成本。只有少量稳定分支时,直接函数或条件判断可能更清楚;模式的价值在于降低变化成本,而不是让类越来越多。
工厂、策略和适配器怎样一起使用?
以“接入多种发券渠道”作为参考设计:业务主流程只依赖统一的发券能力;渠道选择规则决定使用哪种策略;每种渠道的适配器负责调用对应 SDK,并转换成统一的业务结果。
新增渠道时,主要增加实现和注册配置,主流程尽量不跟随变化。工厂或注册表解决“怎样取得合适对象”,策略解决“这次使用哪种行为”,适配器解决“外部接口怎样接入”。不能因为几个类都实现同一个接口,就把这些意图混成一种模式。
设计还需要处理未知渠道、重复注册、初始化失败和不同渠道的错误语义;这些不会因用了模式就自动消失。若实现被复用,也不能把本次请求的用户、金额等可变状态随意保存在共享实例字段里。
项目中的实际例子怎样对应?
电商问数教程的客户端管理层提供了一个具体例子:模块中创建 Embedding 客户端管理器,应用启动时显式初始化,其他模块通过这一入口复用客户端;MySQL 管理器则分别面向元数据库和教学数仓,持有各自的 Engine 与会话工厂,使用时再创建会话。
这里让资源创建和业务调用分开:Engine 与客户端可以复用,会话状态按使用范围管理。模块级共享通常以单个应用进程为范围,多进程部署时各进程仍可有自己的管理器;它与通过构造机制限制类实例数量的单例模式有所不同。
如果后续要支持多种 Embedding 服务,可以在当前集中管理的基础上设计统一接口,由适配器转换各服务的参数和结果,再按模型能力、成本等条件选择实现。这是从现有客户端管理继续扩展的一个方向。
常见追问
适配器和装饰器都包装对象,有什么区别? 适配器解决接口或语义不兼容,装饰器侧重在兼容接口下增强能力。要看它解决的问题,而不是只看有没有一层包装。
策略是否消除了所有 if/else? 选择规则仍然需要存在,可能放在配置、注册表或选择器中。改善的是业务主流程和具体规则之间的耦合,并不要求把所有判断都隐藏起来。
单例是不是整个系统唯一? 必须说明范围,例如应用进程、类加载器或容器。多个实例部署仍可能各有一份共享对象;跨进程协调需要另行设计。
对应教程
- 电商问数:MySQL、Embedding与日志管理:客户端管理器和 Engine、Session 的生命周期部分,展示模块级复用、集中初始化及按使用范围创建会话的实际组织方式。
参考资料
- 国内:JavaGuide:Java IO设计模式总结:装饰器与适配器的接口关系和组合方式,用于解释两种包装结构各自解决的问题,以及为何支持叠加不等于接口转换。
- 国内:嘉凯、杨柳 / 美团:设计模式二三事:发券策略、渠道适配和共享策略实例的演进,用于说明模式如何隔离变化,以及选择器和共享状态仍需设计。
- 国内:亮亮 / 美团:设计模式在外卖营销业务中的实践:返奖规则中的工厂与策略职责,用于区分创建对象和替换业务规则,并把选型放回具体业务变化中。
- 国外:Refactoring.Guru:Strategy:意图、适用性和优缺点部分,用于说明可替换行为的收益、选择责任,以及稳定少量算法不必增加类型体系。
- 国外:Refactoring.Guru:Factory Method:创建者、产品接口与优缺点部分,用于准确解释工厂方法的扩展点,并区分一般的集中创建代码与该模式的具体结构。


