策略模式

声明 本文内容属于《Head First 设计模式》阅读笔记,文中涉及到的知识案例等直接或间接来源于该书。《Head First 设计模式》通过有趣的图表+文字的形式,让人自然学习设计模式,非常棒推荐阅读


策略模式概念

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


案例(辅助理解)

提示 策略模式使用灵活,下面只是一个简单的例子,在不同的情境下,可能有不同的表现形式。

情景介绍

       现在有一个鸭子游戏,所有的鸭子都能游泳swim,都有自己的外观display。部分鸭子能飞,而且飞的方式可能各不一样,部分鸭子能叫,可能叫的方式也各不一样。

普通方式

       因为所有的鸭子都能游泳swim,都有自己的外观display,所以使用继承的方式,创建父类鸭,父类鸭有swim以及display方法,各个不同的子类鸭均继承父类鸭,这下各个子类鸭就有了swim和display的能力了(如果有需要,还可以进行方法重写);然后对于飞行和叫,可以抽象为接口,各个子类鸭根据自己的不同的情况,实现飞行接口、叫接口即可。

使用策略模式的方式

       对于飞和叫这样的行为,单独抽取为行为两个接口,并对这两个接口分别进行算法族实现(即:一系列实现)。创建父类鸭,父类鸭本身不仅有swim和display的能力,还持有两个接口。各子类鸭只需要对这两个接口属性提供不同的策略实现即可。当子类有对飞或对叫的功能变化的需求时,可以通过setter方法进行切换。UML图如下所示:
策略模式_第1张图片在父类鸭中可以将飞行为或叫行为委托给策略算法族了:
策略模式_第2张图片这样一来,在子类鸭继承父类鸭时,主动指定具体的飞行为或叫行为即可,如:
策略模式_第3张图片就算在程序中,想要切换子类鸭的飞行为或叫行为,只需要使用setter方法指定即可,如:
策略模式_第4张图片       如果直接用子类实现飞行为或叫行为的接口的话,那么具体的行为就和具体的鸭死死绑定在了一起,程序扩展性维护性差,此时使用策略模式优势一览无疑。

上述策略模式示例中的几个核心类

  • Duck
    import com.szlaozicl.designpattern.strategy.fly.FlyBehavior;
    import com.szlaozicl.designpattern.strategy.quack.QuackBehavior;
    import lombok.Getter;
    import lombok.Setter;
    
    /**
     * 父类鸭
     *
     * 注: 如果是在各个子类中直接实现FlyBehavior或QuackBehavior的话,那么子类的
     *     飞或叫行为就是定死了的。而如果将其作为一个属性的话,那么子类中可以通
     *     过setter等方式来指定其具体实现,从而达到切换子类能力的功能。
     *
     * @author JustryDeng
     * @date 2019/10/1 19:47
     */
    public class Duck {
    
        /** 飞 属性 */
        @Setter
        @Getter
        protected FlyBehavior flyBehavior;
    
        /** 叫 属性 */
        @Setter
        @Getter
        protected QuackBehavior quackBehavior;
    
        /**
         * 所有鸭子都能游泳
         */
        public void swim() {
            System.out.println("鸭子游泳咯!");
        }
    
        /**
         * 所有鸭子都有外观
         */
        public void display() {
            System.out.println("鸭子外观 ma gia gia 的!");
        }
    
        /**
         * 调用flyBehavior的fly方法
         *
         * 即:这里将 飞 委托给了flyBehavior的具体实现
         */
        public void performFly() {
            flyBehavior.fly();
        }
    
        /**
         * 调用quackBehavior的quack方法
         *
         * 即:这里将 叫 委托给了quackBehavior的具体实现
         */
        public void performQuack() {
            quackBehavior.quack();
        }
    }
    
  • DecoyDuck
    /**
     * 诱饵鸭
     *
     * @author JustryDeng
     * @date 2019/10/1 20:05
     */
    @SuppressWarnings("unused")
    public class DecoyDuck extends Duck {
    
        /**
         * 构造方法
         *
         * 注:在构造方法中指定初始化的 飞 和 叫 的行为实现
         */
        public DecoyDuck() {
            // 诱饵鸭  能火箭助力飞, 能呱呱叫
            this.flyBehavior = new FlyRocketPowered();
            this.quackBehavior = new Quack();
        }
    
        /// other....
    }
    
  • FlyBehavior
    /**
     * 飞
     *
     * @author JustryDeng
     * @date 2019/10/1 19:50
     */
    public interface FlyBehavior {
    
        /**
         * 飞
         */
        void fly();
    }
    
  • FlyRocketPowered
    /**
     * 火箭助力飞 实现
     *
     * @author JustryDeng
     * @date 2019/10/1 20:11
     */
    public class FlyRocketPowered implements FlyBehavior {
    
        @Override
        public void fly() {
            System.out.println("火箭助力飞~");
        }
    }
    
  • FlyWithWings
    /**
     * 用翅膀飞
     *
     * @author JustryDeng
     * @date 2019/10/1 19:52
     */
    public class FlyWithWings implements FlyBehavior {
    
        @Override
        public void fly() {
            System.out.println("用翅膀飞~");
        }
    
    }
    
  • QuackBehavior
    /**
     * 叫
     *
     * @author JustryDeng
     * @date 2019/10/1 19:51
     */
    public interface QuackBehavior {
    
        /**
         * 叫
         */
        void quack();
    }
    

^_^ 如有不当之处,欢迎指正

^_^ 参考资料
        《Head First 设计模式》
Eric Freeman & Elisabeth Freeman with Kathy Sierra & Bert Bates著,O’Reilly Taiwan公司译,UMLChina改编

^_^ 测试代码托管链接
         https://github.com/JustryDeng…DesignPattern

^_^ 本文已经被收录进《程序员成长笔记(六)》,笔者JustryDeng

你可能感兴趣的:(Head,First设计模式)