设计模式-策略模式
策略模式(Strategy)行为型模式
策略模式模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户中。
OO原则:针对接口编程,而不是针对实现编程。
针对接口:指的是制造其它类专门实现接口,由行为类来实现行为接口,指的就是针对超类型编程。
针对实现:指的就是具体实现超类方法或者继承某个接口并且由子类实现。
下面就拿Duck例子来说明策略模式:
以前的做法:行为来自Duck超类的具体实现,或是继承某个接口并且由子类自行实现而来;这两种做法都是依赖于“实现”。
新设计:鸭子的子类将使用接口所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类(MallarDuck、RedheadDuck等)中,换句话说,特定的具体行为编写在实现了FlyBehavior与QuackBehavior中。
从现在开始,鸭子的行为将被放在分开的类中,此类专门提供某行为接口的实现。这样,鸭子类就不再需要知道行为的实现细节。
下面是我们要使用的例子Duck的UML图:
Duck的UML图
下面是UML图中每个部分的具体代码:
Duck类
/* Duck类 */ public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck(){} public abstract void display(); public void performFly(){ flyBehavior.fly(); } public void performQuack(){ quackBehavior.quack(); } public void swim(){ System.out.println("All ducks float ever decoys!"); } // 通过setter method来设定鸭子的行为,而不是在鸭子构造器内实例化 public void setFlyBehavior(FlyBehavior fb){ flyBehavior = fb; } public void setQuackBehavior(QuackBehavior qb){ quackBehavior = qb; } }
FlyBehavior接口与两个行为实现类(FlyWithWings.java与FlyNoWay.java)
/* FlyBehavior接口与两个行为实现类(FlyWithWings.java与FlyNoWay.java) */ public interface FlyBehavior { public void fly(); } public class FlyWithWings implements FlyBehavior { public void fly(){ System.out.println("I'm flying"); } } public class FlyNoWay implements FlyBehavior { public void fly(){ System.out.println("I can't flying"); } }
QuackBehavior接口及其三个实现类(Quack.java,MuteQuack.java,Squeak.java)
/* QuackBehavior接口及其三个实现类(Quack.java,MuteQuack.java,Squeak.java) */ public interface QuackBehavior { public void quack(); } public class Quack implements QuackBehavior { public void quack(){ System.out.println("Quack"); } } public class MuteQuack implements QuackBehavior { public void quack(){ System.out.println("<< Silence >>"); } } public class Squeak implements QuackBehavior { public void quack(){ System.out.println("Sqeak"); } }
MallardDuck类
/* MallardDuck类 绿头鸭使用Quack类来处理呱呱叫,所以当performQuack()被调用的时候,叫的职责被委托给Quack对象,而我们得到的了真正的呱呱叫 */ public class MallardDuck extends Duck { // 别忘了,因为MallardDuck继承了Duck类,所以具有flyBehavior和quackBehavior实例变量 public MallardDuck(){ quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display(){ System.out.println("I'm a real Mallard Duck~"); } }
测试类
/* 测试类 */ class MiniDuckSimulator { public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performQuack(); // 调用继承来的quackBehavior引用对象的quack() mallard.performFly(); } }
结果:
下面我们做些变化来展现策略模式的优点
创建一个新的鸭子类:模型鸭(ModelDuck.java)
/* 创建一个新的鸭子类:模型鸭(ModelDuck.java) */ public class ModelDuck extends Duck { public ModelDuck(){ flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public void display(){ System.out.println("I'm a model duck"); } }
建立一个新的FlyBehavior类型(FlyRocketPoered.java)
/* 建立一个新的FlyBehavior类型(FlyRocketPoered.java) */ public class FlyRocketPowered implements FlyBehavior { // 建立了一个利用火箭动力的飞行行为 public void fly(){ System.out.println("I'm flying with a rocket!"); } }
对原先的测试进行以下修改:
通过set方法来动态设置需要改变的模块
加上模型鸭(ModelDuck),并使模型鸭拥有火箭动力
修改后的测试类
/* 测试类 */ class MiniDuckSimulator { public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performQuack(); // 调用继承来的quackBehavior引用对象的quack() mallard.performFly(); System.out.println("下面是模型鸭的动态添加功能!"); // 改变测试类,通过set方法来动态设置需要改变的模块 // 加上模型鸭(ModelDuck),并使模型鸭拥有火箭动力 Duck model = new ModelDuck(); model.performFly(); // 调用继承来的setter方法,把火箭动力飞行的行为设定到模型鸭中。 model.setFlyBehavior(new FlyRocketPowered()); model.performFly(); } }
实验结果:
实验总结:
在运行时想改变鸭子的行为,只需调用鸭子的setter方法即可,从而实现了在运行时动态的改变行为。
从策略模式中得到的总结:
以上就是策略模式的应用之一,在上面的那个例子中,将FlyBehavior和QuackBehavior等行为的具体实现都封装起来,并且可以相互替换(通过setter方法),此模式让算法的变化独立于使用算法的客户。满足了针对接口编程,而不是针对实现编程,即由行为类(Quack、Squeak、MuteQuack等)来实现接口(FlyBehavior和QuackBehavior)而不是Duck类来实现行为接口,所以实际的“实现”(RedheadDuck、ModelDuck等)不会被绑死在鸭子的子类中,从而提高了代码的弹性。
上一篇: IIS7.5中配置PHP运行环境全程实录
下一篇: RxJava的消息订阅和线程切换原理