设计模式--策略模式

ps:本文主要来源于Head First 设计模式(抄Head First的),如有不懂请购买原书观看。

策略模式定义: 定义了算法簇,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

举个例子:

假设有个Duck(鸭子)父类,鸭子有很多子类,都继承于duck,比如MallardDuck,RedheadDuck, RubberDuck,DecoyDuck.

Duck 类有 quack(),swim(),display(), fly()等方法。这样子类都有了父类的方法。这样有个缺点,比如有的子类不该有fly()这个方法,现在也有了,

RubberDuck (橡皮鸭)就不能飞。

解决这个问题有一个方法,就是把fly()方法覆盖掉,不做任何事就ok了。这样本也没什么大问题,但当我加入了新的鸭类后,比如加了 DecoyDuck(诱饵鸭),也不会飞,这样又要覆盖掉fly()方法。这样代码就重复了。

那么把 fly()方法提前出来,放进一个Flyable接口中,接口有fly()方法,那个鸭子类需要fly()行为,就实现Flyable接口。这样是能解决了RubberDuck与DecoyDuck鸭的飞行问题,这两类鸭再也不会飞。但这又带来新问题,就是不能复用fly()方法了,本来很多类鸭子的fly()都差不多(甚至一样),现在要一个一个实现。

ps: 1.把应用中可能需要变化的部分独立出来,不要和那些不需要变化的代码混到一起。

2.针对接口编程,而不是针对实现编程,即(Animal animal = new Dog()或者Map map = new HashMap(),而不是 Dog d=new Dog,)

回到上面的问题,解决的办法仍然是把fly()抽象出来成为一个接口,接口可以叫FlyBehavior,或者别的FlyInteface也行,接着针对不同的飞行行为写不同的实现类,比如 FlyWithWings,FlyNotWay类实现FlyBehavior,在类里面实现不同飞行方式。这样设计,可以让飞行动作被其它对象复用,不仅仅是鸭子类,这个飞行行为已经与鸭子类无关了。还可以在FlyWithWings里面增加别的动作比如run()等,也不会影响鸭子类使用fly()。

这样Duck类可以使用FlyBehavior了,在Duck类 新加 FlyBehavior flyBehavior;

可以在Duck构造器初始化FlyBehavior,

public class MallardDuck extends Duck{


public MallardDuck(){

    flyBehavior = new FlyWithWings();

}

public void performFly(){

flyBehavior.fly()

}

}

这样鸭子不必亲自出来fly()动作了,可以委托(delegate)给别人处理(FlyBehavior).

上面已经很好了,但仍有不足,就是我们在MallardDuck构造器初始化 FlyBehavior 为FlyWithWings实例,这是针对具体实现编程,如何动态设定这个行为呢,就是我本来飞行行为是FlyWithWings,后来我又想换成FlyWithRockey。


可以在Duck类新加set方法,

public void setFlyBehavior(FlyBehavior fb){

flyBehavior = fb;

}

来看一下部分代码

Duck model = new ModelDuck();

model.performFly();  //这里输出 构造器里初始化的飞行方法 比如 i am fly with wings

model.setFlyBehavior(new FlyRockerPowered());

model.performFly(); //这里输出修改后的飞行方法,比如  i am fly with rocker powered


ps:多用组合,少用继承。(“有一个”可能比“是一个”更好)

我们描述事物的方式有些改变,不再把鸭子的行为说成“一组行为”,我们把行为想成是“一簇算法”。(这样的做法也能很容易用一群类来计算不同州的销售税金)。


策略模式在jdk中的应用有比较器Comparator和布局管理器LayoutManager

你可能感兴趣的:(设计模式--策略模式)