策略设计模式
程序员文章站
2022-03-10 17:38:56
模式定义 定义一系列算法,分别封装起来,让它们之间可以呼死去那个替换,此模式让算法变化,不会影响到使用算法的客户 类图定义 示例 示例来自于Head First上的鸭子例子,一个鸭子的系统,系统中会出现不同的鸭子,一边游泳一边叫。绿头鸭子会飞,会游泳,正常呱呱叫,橡皮鸭子不会飞不会游泳吱吱叫。后期可 ......
模式定义
定义一系列算法,分别封装起来,让它们之间可以呼死去那个替换,此模式让算法变化,不会影响到使用算法的客户
类图定义
示例
示例来自于Head First上的鸭子例子,一个鸭子的系统,系统中会出现不同的鸭子,一边游泳一边叫。绿头鸭子会飞,会游泳,正常呱呱叫,橡皮鸭子不会飞不会游泳吱吱叫。后期可能会扩展其他的鸭子比如红头鸭子或者诱饵鸭。鸭子系统的设计类图如下
首先创建鸭子类
/** * 鸭子抽象类 * * @author Colin * @create 2018-02-25 **/ public abstract class Duck { private FlyBehavior flyBehavior; private QuackBehavior quackBehavior; public Duck(){} /** * 外观显示方法 */ public abstract void display(); public void swim(){ System.out.println("我们都是鸭子,我们都会游泳!"); } /** * 飞行 */ public void performFly(){ flyBehavior.fly(); } /** * 叫 */ public void performQuack(){ quackBehavior.quack(); } public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } }
鸭子具体实现类
/** * 绿头鸭子 * * @author Colin * @create 2018-02-25 **/ public class MallardDuck extends Duck{ @Override public void display() { System.out.println("我是绿头鸭子!"); } }
/** * 橡皮鸭子 * * @author Colin * @create 2018-02-26 **/ public class RebberDuck extends Duck { @Override public void display() { System.out.println("我是橡皮鸭子!"); } }
创建鸭子飞行和叫的接口和实现类,不同的鸭子叫声或者是飞行的方式不一样,所以相对于整个系统来说这块是可变的,单独提取封装起来。
/** * 飞行行为 * * @author Colin * @create 2018-02-25 **/ public interface FlyBehavior { public void fly(); } /** * 叫的行为 * * @author Colin * @create 2018-02-25 **/ public interface QuackBehavior { public void quack(); }
/** * 不会飞行 * * @author Colin * @create 2018-02-25 **/ public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("我不会飞!"); } } /** * 飞行具体实现类 * * @author Colin * @create 2018-02-25 **/ public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("我会飞!"); } }
/** * 呱呱叫 * * @author Colin * @create 2018-02-25 **/ public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("正常鸭子呱呱叫!"); } } /** * 吱吱叫 * * @author Colin * @create 2018-02-25 **/ public class Squack implements QuackBehavior { @Override public void quack() { System.out.println("橡皮鸭子吱吱叫!"); } }
测试类
/** * 鸭子测试类 * * @author Colin * @create 2018-02-25 **/ public class DuckTest { @Test public void testMallardDuck(){ // 绿头鸭子会呱呱叫,会飞 Duck duck=new MallardDuck(); duck.setFlyBehavior(new FlyWithWings()); duck.setQuackBehavior(new Quack()); duck.display(); duck.performFly(); duck.performQuack(); } @Test public void testRebberDuck(){ Duck duck=new RebberDuck(); duck.setFlyBehavior(new FlyNoWay()); duck.setQuackBehavior(new Squack()); duck.display(); duck.performFly(); duck.performQuack(); } }
总结
-
上面的例子其实就是一个策略模式的应用,不同的鸭子有不同的飞行策略和叫的方式,所以单独定义飞行和叫的接口即策略模式中的策略接口,不同的的叫声或者飞行方式实现接口即不同的策略类。鸭子Duck类中组合这些策略,即Duck就是策略中的上下文,所有的变化行为都是在此定义。后期扩展其他鸭子时只需继承Duck 然后设定这个鸭子拥有的行为即可有很大的灵活性。
涉及到的设计原则
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程(多态,利用多态程序可以针对超类编程执行时会根据实际的情况执行到真正的行为不会被绑死到超类型的行为上)
多用组合,少用继承(使用组合系统具有很大的弹性,不仅可以将算法封装成类更可以在运行时动态改变行为)