背景
现在父类加入一个 fly(),子类中加入一个橡皮鸭不会嘎嘎叫,因此 quack() 被重写为“Squeak”(吱吱叫声)
问题
- 固定行为: 所有的鸭子子类都继承了默认的
quack和fly行为,这意味着这些行为是固定的。如果某个具体的鸭子子类需要不同的行为,就需要修改现有的继承链或者引入新的子类,导致类的爆炸问题。 - 耦合性高: 所有的鸭子子类都强烈依赖于父类的实现。如果有新的需求需要添加一种新的行为,可能会影响到所有的鸭子子类。
- 可维护性差: 如果鸭子的某个子类需要修改继承的行为,就必须在子类中进行修改,可能导致代码的脆弱性和可维护性下降。
- 不灵活: 难以在运行时动态改变行为,因为行为是通过继承而来的,而不是可以随时替换的组件。
设计原则
封装变化
- 识别应用程序中会发生变化的方面,并将其与保持不变的部分分离。
- 将会变化的部分进行封装,以便以后可以修改或扩展变化的部分,而不影响那些保持不变的部分。
- Program to an interface, not an implementation.
其他类型的对象可以重用我们的飞行和嘎嘎叫行为,因为这些行为不再被硬编码在我们的 Duck 类中。 我们可以添加新的行为,而无需修改任何现有的行为类或触及使用飞行行为的 Duck 类。
改进
我们在运行时改变行为:
定义
- 策略接口(Strategy Interface): 定义了所有支持的算法的通用接口。
- 具体策略(Concrete Strategy): 实现了策略接口,提供具体的算法实现。
- 上下文(Context): 包含一个对策略接口的引用,通常是通过该接口来调用具体的算法。上下文可以在运行时动态切换不同的策略。
- 策略模式 意图:
- 定义一族算法,将每个算法封装起来,并使它们可以互换使用。策略模式使得算法的变化独立于使用它的客户端。 也称为:
- 策略模式 也被称为 Policy 模式