zoukankan      html  css  js  c++  java
  • 设计模式(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就可以实现了。

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

  • 相关阅读:
    MQTT TLS 加密传输
    python多进程并发redis
    各种消息队列的特点
    mqtt异步publish方法
    Numpy API Analysis
    Karma install steps for unit test of Angular JS app
    reinstall bower command
    Simulate getter in JavaScript by valueOf and toString method
    How to: Raise and Consume Events
    获取对象的类型信息 (JavaScript)
  • 原文地址:https://www.cnblogs.com/oeleven/p/10328508.html
Copyright © 2011-2022 走看看