策略模式.
2019-11-30

    网上介绍设计模式的文章有很多,好文也不少。作为设计模式的初学者,实在不敢多加造次。就仅以此文作为我记忆的备忘录吧!

一、介绍    

    策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:”准备一组算法,并将每一个算法封装起来,使得它们可以互换”。

    这个模式涉及到三个角色:

环境(Context):持有一个策略的引用。抽象策略(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。具体策略(ConcreteStrategy):包装了相关的算法或行为,表示具体的实现方式。

二、Demo实现

    理论看的再多,还不如一个 Demo 让人简单易懂:

public class Duke { /** * 策略对象 - 鸭子叫行为 */ private Quackbehavior quackbehavior; /** * 策略对象 - 鸭子飞行行为 */ private FlyBehavior flyBehavior; /** * 利用多态注入具体的策略对象 */ public Duke(Quackbehavior quackbehavior, FlyBehavior flyBehavior) { this.quackbehavior = quackbehavior; this.flyBehavior = flyBehavior; } /** * 策略方法 */ public void performFly() { flyBehavior.fly(); } /** * 策略方法 */ public void performQuack() { quackbehavior.quack(); } // 其他方法}

   Duke类在策略模式中扮演一个环境(Context)的角色,表示持有策略的引用(quackbehavior、flyBehavior)。

public interface Quackbehavior { void quack();}

public interface FlyBehavior { void fly();}

   这两个接口在策略模式中扮演抽象策略(Strategy)的角色,把公共的行为封装成接口。

    Quackbehavior 的实现类:

public class Quack implements Quackbehavior { @Override public void quack() { System.out.println("嘎嘎叫..."); }}Quack.java

public class Squeak implements Quackbehavior { @Override public void quack() { System.out.println("吱吱叫..."); }}Squeak.java

public class MuteQuack implements Quackbehavior { @Override public void quack() { System.out.println("不会叫..."); }}MuteQuack.java

     FlyBehavior 的实现类:

public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("不会飞..."); }}FlyNoWay.java

public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("正在飞翔..."); }}FlyWithWings.java

     这两对实现类在策略模式中扮演具体策略(ConcreteStrategy)的角色,表示具体的实现行为。  

public class Test { public static void main(String[] args) { DivingDuck divingDuck = new DivingDuck(new Quack(), new FlyWithWings()); ToyDuck toyDuck = new ToyDuck(new MuteQuack(), new FlyNoWay()); divingDuck.performQuack(); divingDuck.performFly(); System.out.println("---华丽的分割线---"); toyDuck.performQuack(); toyDuck.performFly(); }}测试类

     演示源代码链接:https://github.com/JMCuixy/design-patterns

三、总结

1、找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。 2、针对接口编程,而不是针对实现编程。 3、多用组合,少用继承。

    第一点的概念很简单,但是它几乎是每个设计模式的精神所在。至于第二点和第三点,我觉得应该放在一起理解,继承导致新建子类行为的不可预知性,因为你不清楚是不是父类所有的行为都适用于子类;而实现却导致代码无法复用,产生大量重复的代码。所以我们考虑了使用组合,最好是使用接口组合,从而可以利用多态注入不同实现,而这正是策略模式的精神呀!

    以下是一些优秀博文的总结:

    策略模式的特点:

1、策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。2、策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。3、运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。

    策略模式的优点:

1、策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。2、使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

    策略模式的缺点:

1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。2、由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很不可观。