在设计模式的学习中,策略模式 (Strategy) 和 装饰模式 (Decorator) 经常让人脸盲。因为它们的代码结构看起很像:都是定义一个接口,都把对象传进去,都利用了多态。
但它们的灵魂完全不同。我们通过两个最经典的案例:'模拟鸭子'和'Java IO 流',彻底搞懂它们的核心区别。
1. 策略模式:核心是'组合与替换' (换芯片)
案例来源:《Head First 设计模式》开篇 —— SimUDuck(模拟鸭子)。
故事背景
假设你设计了一套鸭子游戏。起初,你用继承的方式,在父类 Duck 里写了一个 fly() 方法。
- 悲剧发生了:系统中还有'橡皮鸭'。因为继承了父类,结果屏幕上出现了一只黄色的橡皮鸭在满天乱飞——这显然是个 Bug。
- 痛点:不是所有的鸭子都会飞,或者飞的方式不一样(有的用翅膀,有的用火箭)。直接写死在父类里,牵一发而动全身。
策略模式的解法:把'变化'抽离出来
策略模式告诉你:既然'飞'这个动作会变,那就把它拿出来,做成一个独立的接口。
- 定义接口:
FlyBehavior(飞行行为)。 - 具体策略:
FlyWithWings(用翅膀飞)FlyNoWay(完全不会飞)FlyRocketPowered(坐火箭飞)
- 组合 (Composition):鸭子类不再自己实现飞,而是持有一个
FlyBehavior对象(就像鸭子身上有个插槽,插入了飞行芯片)。
代码演示
Java 代码实现:
public class Duck { // 关键点:鸭子'有一个'飞行策略,而不是鸭子'是'飞行家 FlyBehavior flyBehavior; // 想怎么飞?看我当时装的是什么策略 public void performFly() { // 委托给策略对象去执行 flyBehavior.fly(); } // 随时可以换策略! public void setFlyBehavior(FlyBehavior fb) { this.flyBehavior = fb; } }
// 客户端使用
Duck modelDuck = new ModelDuck(); // 刚开始是模型鸭,不会飞
modelDuck.setFlyBehavior(new FlyNoWay());
modelDuck.performFly(); // 输出:<< 我无法飞行 >>
// 突然给它装上火箭配件!(运行时动态替换)
modelDuck.setFlyBehavior(new FlyRocketPowered());
modelDuck.performFly();


