为什么使用策略模式?
分析一个鸭子父类和各种鸭子子类之间的fly()方法如何写。
有几点需要注意,先是不通鸭子飞的方式可能不一样,甚至有的鸭子不会飞。
①如果直接在父类中加入fly()的实现,那么所有的子类鸭子都只会同一种飞法,这肯定是不对的。
②如果在子类中重写父类的fly()方法,那么以后每加入一个新品种鸭子,都需要重写fly()函数。
③直接继承fly()方法可能不是最佳答案,如果利用接口呢?我们将fly()从父类中取出,放进一个Flyable接口中,只有会飞的鸭子需要实现这个接口。看似可行,但是这使得代码不可复用,每个子类都必须实现fly()方法。
使用原因:
类似的,在实现某一个功能时有多重算法或者策略,我们根据不同环境和条件选择不同的算法和策略来完成此功能。
在这基础上,我们还需要一种对已有代码影响最小的方式来修改代码,并且可以花费较少时间来重写代码。
什么是策略模式?
策略模式:定义了算法族,分别封装起来,让他们(每种算法)之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计原则①:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
设计原则②:针对接口编程,而不是针对实现编程。
根据设计原则①,分析我们的类,我们很容易发现,fly()方法是现在变化的部分,所以我们应当将fly()单独拿出。
根据设计原则②,我们应当将fly设置为一个接口,然后下面有不同的实现此接口的类。
然后开始整合:
①需要在原duck类中“加入一个实例变量”,“flyBehavior”,声明为接口类型(而不是具体类实现类型),每个鸭子对象都会动态的设置这些变量以在运行时引用正确的行为类型。
②在实现duck的fly函数的时候只需要调用“flyBehavior”接口的fly方法即可。
③如何制定“flyBehavior”接口的具体实现?只需在duck的子类的构造函数中,为“flyBehavior”接口指向一个具体实现即可。
如
public class MallardDuck extends Duck{ public MallardDuck(){ flyBehavior=new FlyWithWings();//将“flyBehavior”接口指向它的具体实现类 }}
到此,基本完成,但是除此之外,我们还以在运行时通过一个setflyBehavior的方法,来重新制定一个鸭子的飞行方式,即应用了多态。
再分析此处应用的策略模式:
算法族:指的是fly接口的不同实现类,因为多态,所以fly接口可以指向它的不同的实现类。
算法的变化独立于客户:因为客户只是调用了fly接口的一个实现类,具体实现类的代码改动并不会影响使调用它的客户的代码进行改动。
选择策略:duck子类的构造函数中为flyBehavior指向一个fly实现类,就是为fly选择了一种算法,也即一种fly策略。