策略模式
策略模式
定义
定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
问题描述
在继承时,我们通常会遇到这样一种场景,父类中的方法并不适合所有的子类。针对这种问题,我们通常有如下3种解决方法:
- 子类覆盖父类中的方法。会有如下问题:
- 代码在多个子类中重复
- 运行时的行为不容易改变
- 父类改变时会牵一发而动全身
- 很难知道所有子类的全部行为
- 把一些方法抽象成接口,而子类实现这些接口。会有如下问题:
- 因为接口没有实现,所以会中造成重复代码变多
- 本文要采用的设计模式(策略模式)
设计原则
- 封装变化,找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
- 针对接口编程,而不是针对实现编程
针对接口编程真正的意思是针对超类型(supertpe)进行编程。针对接口编程,关键就在多态。利用多态,程序可以针对超类型编程,执行时会根据实际情况执行到真正的行为,不会被绑死在超类型的行为上。
- 多用组合,少用继承
- 当你将两个类结合起来使用时,就是组合(composition)。鸭子的行为不是继承来的,而是和适当的行为对象”组合“来的。
实战
// parent class
public class Duck {
// 将quackBehavior声明为接口类型(而不是具体类实现类型),每个鸭子对象都会动态地设置这些变量以在运行时引用正确的行为
QuackBehavior quackBehavior;
FlyBehavior flyBehavior;
public void performQuack() {
quackBehavior.quack();
}
public void performFfy() {
flyBehavior.fly();
}
// 通过在超类中设置set方法,可以在运行时动态改变飞行的行为
// 也就是使用组合建立系统具有很大的弹性,不仅可以将算法族封装成类。更可以在运行时动态地改变行为
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
}
// child class
public class MallardDuck extends Duck {
public MallardDuck() {
// MallardDuck继承自Duck,所以具有相同的实例变量
// quackBehavior在子类中被实例化成具体的对象,在执行performQuack()(在父类中定义)调用时,叫的职责被委托给Quack对象了。
quackBehavior = new Quack();
flyBehavior = new Fly();
...
}
}
public static void main() {
Duck mallardDuck = new MallardDuck();
// 在运行时,动态地改变飞行的行为
mallardDuck.setFlyBehavior(new FlyRocketPowered());
mallardDuck.performFly();
}
鸭子的行为堪称是一族算法
== 未完,待续 ==