Photo by Lorem Ipsum
1043 words
5 minutes
设计模式系列(四):易混淆辨析
设计模式系列
Posts in this series (7)AI 智能总结
设计模式 4 易混淆辨析
开发与面试经常分不清几组外观相似的模式,核心区分方式:看设计目标、接口是否变化、意图,附带代码特征对比。
1. 装饰器 vs 适配器 vs 代理
三者都采用「包装对象」的形式,最容易混淆。
核心结论
- 装饰器:接口不变,增强功能
- 适配器:转换接口,兼容异构
- 代理:控制访问,管控原始对象
装饰器(Decorator)
目标:动态叠加功能,原始接口保持不变
包装类与被包装类实现同一个接口,可以多层嵌套拓展。
interface Coffee{ double cost();}class SimpleCoffee implements Coffee{ @Override public double cost(){return 10;}}// 装饰器,实现相同接口class MilkDecorator implements Coffee{ private Coffee coffee; public MilkDecorator(Coffee coffee){this.coffee = coffee;} @Override public double cost(){ return coffee.cost() + 3; }}适配器(Adapter)
目标:接口转换,解决两个类接口不兼容
新旧接口不一样,做翻译层,不侧重增强功能。
// 新系统标准接口interface Target {void handle();}// 老系统类,方法名不一致class OldService {void oldHandle(){}}// 适配器做转换class ServiceAdapter implements Target{ private OldService oldService; @Override public void handle() { oldService.oldHandle(); }}代理(Proxy)
目标:控制对真实对象的访问,增加预处理/后置处理
接口和真实对象保持一致,重点是访问管控(权限、延迟加载、AOP)。
interface UserService{ void query();}class UserServiceImpl implements UserService{}// 代理类class UserProxy implements UserService{ private UserService target; @Override public void query() { System.out.println("前置校验"); target.query(); }}快速区分口诀:
- 同接口、叠加功能 → 装饰器
- 接口不一样、做兼容转换 → 适配器
- 同接口、管控对象访问 → 代理
2. 工厂 vs 建造者
共同点:都负责对象创建;区别在于对象复杂度与创建方式
工厂模式(工厂方法/抽象工厂)
关注点:整体产出完整对象,不需要关心构建步骤。
适用:产品结构简单,一次性创建完成。
建造者(Builder)
关注点:分步构造复杂对象,对象属性繁多、构造流程复杂。
适用:对象存在大量可选参数,构造步骤固定,但细节可变。
// Builder示例class Person { private String name; private Integer age; // 私有构造 private Person(Builder builder){ this.name = builder.name; this.age = builder.age; } public static class Builder{ private String name; private Integer age; public Builder name(String name){ this.name = name; return this; } public Builder age(Integer age){ this.age = age; return this; } public Person build(){ return new Person(this); } }}// 使用:分步赋值Person p = new Person.Builder().name("test").age(20).build();区分要点:
- 一次性生成产品 → 工厂
- 分步骤组装、参数众多 → 建造者
3. 策略 vs 状态
结构高度相似,都有上下文Context、多个实现类,是面试重难点。
策略模式
- 算法之间互相独立,主动切换
- 上下文主动传入/设置策略;策略之间互不感知
- 示例:支付方式、折扣算法
interface PayStrategy{ void pay();}class AliPay implements PayStrategy{}class PayContext{ private PayStrategy strategy; public void setStrategy(PayStrategy s){this.strategy = s;}}状态模式
- 状态自动流转,状态之间具备关联性
- 对象内部状态发生变化,自动切换行为;状态类可以驱动状态变更
- 示例:订单状态(待支付→已支付→已取消)
// 状态接口interface OrderState { void pay(OrderContext order); void cancel(OrderContext order);}
// 待支付状态class WaitingPayState implements OrderState { public void pay(OrderContext order) { // 支付成功,切换到已支付状态 order.setState(new PaidState()); } public void cancel(OrderContext order) { order.setState(new CanceledState()); }}
// 订单上下文class OrderContext { private OrderState state; public void setState(OrderState state) { this.state = state; // 状态自动流转切换 }}区分要点:
- 人为主动选择不同算法,算法无关联 → 策略
- 对象自身状态自动流转,状态之间存在切换逻辑 → 状态
总结一览
| 分组 | 核心区分点 |
|---|---|
| 装饰器/适配器/代理 | 功能增强 / 接口转换 / 访问控制 |
| 工厂/建造者 | 一次性创建对象 / 分步组装复杂对象 |
| 策略/状态 | 主动选择独立算法 / 对象内部自动流转状态 |
实践提醒:不要只看代码结构,优先思考业务意图,才能准确选用模式。