• 设计模式(1)策略模式


    先假设我们要做一个模拟鸭子的游戏,这群鸭子会在水里游泳、会嘎嘎的叫,那么运用OO的思想,先设计一个鸭子作为父类,然后所有的鸭子都继承这个父类。

    现在,鸭子模拟游戏1.0版本就诞生了,这些鸭子继承了父类的游泳、嘎嘎叫,以及各自都有自己的描述。

    接下来就是开发鸭子模拟游戏2.0了,现在需要给鸭子扩展一些模拟,例如飞行、还要给鸭子扩展一些种类,例如模型鸭、橡皮鸭。

    这时候就可以继续扩展鸭子父类的属性,并且多添加几个子类。

    由于模型鸭、橡皮鸭不会叫也不会飞,所以在子类中重载了quack()方法和fly()方法。

    但是这个设计也是不合理的,因为每次有新的鸭子出现,就需要对quack()和fly()进行检查,判断这个类型的鸭子需不需要覆盖这两个方法,需要有一种更清晰的方法。

    于是鸭子模拟游戏2.1版本就这样诞生了,这个时候将fly()和quack()从父类中提取出来,放入到两个接口中去,只有会飞、会嘎嘎叫的鸭子才会去继承这两个接口。

    但是这样设计出来的结构,也是有缺陷的,例如Mallard和RedheadDuck它们的叫声都是“嘎嘎”,但是却写了重复的quack()代码,没有实现代码的复用。

    我们需要重新考虑下这个鸭子模拟游戏整体的设计了,首先鸭子的fly()和quack()行为会频繁的根据鸭子的种类进行变化,基于设计原则——找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码放在一起。我们可以把鸭子的fly()和quack()行为独立出来,从Duck类中提出,建立一组新类代表这些行为。

    鸭子fly()的方式会有多种,如有的鸭子是普通的飞行、有的鸭子是鸭子中的战斗鸭,它们的飞行就是特技飞行了。但是无论它们以何种方式进行飞行,它们都是属于飞行这一个行为。再考虑到鸭子会进行锻炼,从一只普通的鸭子变成了战斗鸭,那它的飞行模式也进行了升级变成了特技飞行,这时就需要能够动态的改变鸭子的飞行行为,基于设计原则——针对接口编程,而不是针对实现编程。我们可以利用接口代表一个行为,如FlyBehavior和QuackBehavior,由fly行为类和quack行为类去具体实现。

    剩下的工作就是把这些行为整合到Duck类中了,可以在Duck定义两个变量,类型为FlyBehavior和QuackBehavior,每个鸭子对象都可以动态的设置这些动作运行时具体的行为类型。

    于是鸭子模拟游戏3.0诞生了

    /**
     * 鸭子飞行为
     *
     * @author ousy
     * @since 2019-01-27 23:21:23
     */
    public interface FlyBehavior {
        /**
         * 鸭子飞行为
         */
        public void fly();
    }
    FlyBehavior
    /**
     * 鸭子叫行为
     *
     * @author ousy
     * @since 2019-01-27 23:21:38
     */
    public interface QuackBehavior {
        /**
         * 鸭子叫行为
         */
        public void quack();
    }
    QuackBehavior
    /**
     * 鸭子普通飞行为
     *
     * @author ousy
     * @since 2019-01-27 23:28:33
     */
    public class NormalFly implements FlyBehavior {
        /**
         * 鸭子飞行为
         */
        @Override
        public void fly() {
            System.out.println("普通的飞");
        }
    }
    NormalFly
    /**
     * 鸭子特技飞行为
     *
     * @author ousy
     * @since 2019-01-27 23:28:41
     */
    public class SpecialFly implements FlyBehavior {
        /**
         * 鸭子飞行为
         */
        @Override
        public void fly() {
            System.out.println("耍特技的飞");
        }
    }
    SpecialFly
    /**
     * 鸭子普通的叫
     *
     * @author ousy
     * @since 2019-01-27 23:28:47
     */
    public class NormalQuack implements QuackBehavior {
        /**
         * 鸭子叫行为
         */
        @Override
        public void quack() {
            System.out.println("鸭子普通的叫");
        }
    }
    NormalQuack
    /**
     * 鸭子特技叫行为
     *
     * @author ousy
     * @since 2019-01-27 23:29:01
     */
    public class SpecialQuack implements QuackBehavior {
        /**
         * 鸭子叫行为
         */
        @Override
        public void quack() {
            System.out.println("鸭子特技的叫");
        }
    }
    SpecialQuack
    /**
     * 鸭子类
     *
     * @author ousy
     * @since 2019-01-27 23:21:57
     */
    public class Duck {
        /**
         * 定义fly行为
         */
        private FlyBehavior flyBehavior;
        /**
         * 定义quack行为
         */
        private QuackBehavior quackBehavior;
    
        /**
         * 游泳
         */
        public void swim() {
            System.out.println("鸭子在水里游泳");
        }
    
        /**
         * 描述
         */
        public void display() {
    
        }
    
        /**
         * 鸭子飞
         */
        public void fly() {
            flyBehavior.fly();
        }
    
        /**
         * 鸭子叫
         */
        public void quack() {
            quackBehavior.quack();
        }
    
        /**
         * 改变飞行行为
         *
         * @param flyBehavior 飞行行为
         */
        public void setFlyBehavior(FlyBehavior flyBehavior) {
            this.flyBehavior = flyBehavior;
        }
    
        /**
         * 改版叫行为
         *
         * @param quackBehavior 叫行为
         */
        public void setQuackBehavior(QuackBehavior quackBehavior) {
            this.quackBehavior = quackBehavior;
        }
    }
    Duck
    /**
     * 普通的鸭子
     *
     * @author ousy
     * @since 2019-01-27 23:32:01
     */
    public class NormalDuck extends Duck {
        /**
         * 鸭子描述
         */
        @Override
        public void display() {
            System.out.println("一只普通的鸭子");
        }
    }
    NormalDuck
    public static void main(String[] args) {
            Duck duck = new NormalDuck();
            duck.display();
            duck.setFlyBehavior(new NormalFly());
            duck.setQuackBehavior(new NormalQuack());
            duck.fly();
            duck.quack();
            System.out.println("普通的鸭子经过了锻炼变成了一只战斗鸭");
            duck.setFlyBehavior(new SpecialFly());
            duck.setQuackBehavior(new SpecialQuack());
            duck.fly();
            duck.quack();
        }
    执行代码

    输出


    一只普通的鸭子
    普通的飞
    鸭子普通的叫
    普通的鸭子经过了锻炼变成了一只战斗鸭
    耍特技的飞
    鸭子特技的叫


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

    这种模式可以用于设计使用多种数据库的组件,例如程序需要根据情况去访问不同的数据库,MySQL、Oracle、SQLServer,可以将各个数据库的连接对象继承一个接口,然后根据具体情况去使用不同的连接。

    策略模式可以很方便的添加新的策略,如鸭子除了NormalQuack、SpecialQuack,它还会WhisperyQuack(轻声的叫),这样就只要创建一个WhisperyQuack类继承QuackBehavior就可以实现了。

    但是它也有缺点,策略的增多不可避免的会导致类越来越多,而且策略之间的算法是平级的,他们不能实现相互的调用。

  • 相关阅读:
    SSH
    Maven仓库
    java中的代理
    R 语言基本操作(基本信息的查看、与本地文件系统交互、编译器版本升级)
    R 语言基本操作(基本信息的查看、与本地文件系统交互、编译器版本升级)
    软件的版本命名管理
    软件的版本命名管理
    递归缩写
    递归缩写
    开源软件的许可(License)
  • 原文地址:https://www.cnblogs.com/oeleven/p/10328508.html
Copyright © 2020-2023  润新知