• 设计模式之策略模式


    情景:

    要设计很多鸭子,每个鸭子都有quack(呱呱叫)和swim功能。

    可以设计一个Duck类,含有quack()和swim()方法就可以了。具体鸭子类继承Duck类。

    新需求:要求添加fly功能。

    如果直接给Duck添加fly()方法,会出现问题,因为有一部分鸭子是不会飞的。

    选择创建Flyable接口,只有会飞的鸭子才继承接口,可以解决这一问题,但是造成代码无法复用。

    设计原则:封装变化

    找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

    因为鸭子的行为是变化的所以把鸭子的行为封装起来,创建一组行为类。

    设计原则:针对接口编程,而不是针对实现编程。

    针对接口编程的意思是: Animal animal = new Dog(); 而不是 Dog dog = new Dog(); 

    Animal可以是超类或者接口,主要是通过多态,使得代码容易被扩展。

    为每个行为写一个接口,行为的具体实现就是接口的一个实现类。这样具体行为就可以容易的被修改。

    行为接口:

    public interface FlyBehavior {
        public void fly();
    }
    -----------
    public interface QuackBehavior {
        void quack();
    }

    实现行为的具体类:

    public class FlyNoWay implements FlyBehavior {
        @Override
        public void fly() {
            System.out.println("I can't fly");
        }
    }
    ……………………
    public class FlyWithWings implements FlyBehavior {
        @Override
        public void fly() {
            System.out.println("I'm flying!");
        }
    }
    ……………………
    public class Quack implements QuackBehavior {
        @Override
        public void quack() {
            System.out.println("Quack");
        }
    }
    ……………………
    public class MuteQuack implements QuackBehavior {
        @Override
        public void quack() {
            System.out.println("<< Silence >>");
        }
    }

    Duck超类:

    public abstract class Duck {
        
        FlyBehavior flyBehavior;
        QuackBehavior quackBehavior;
        
        public Duck() {
        }public void performFly() {
            flyBehavior.fly();    // 委托给行为类
        }
        
        public void performQuack() {
            quackBehavior.quack();
        }
        
        public void swim() {
            System.out.println("All ducks flost, even decoys!");
        }
        
        public void display() {
            System.out.println("I am a duck.");
        }
        
    }

    Duck一个具体实现类:

    public class MallardDuck extends Duck {
        public MallardDuck() {
            quackBehavior = new Quack();
            flyBehavior = new FlyWithWings();
        }
        public void display() {
            System.out.println("I'm a real Mallard duck.");
        }
    }

    测试类:

    public class MiniDuckSimulator {
        public static void main(String[] args) {
            Duck mallard = new MallardDuck();
            mallard.performQuack();
            mallard.performFly();
        }
    }

    输出:

    Quack
    I'm flying!

    如果能在Duck类中通过setter动态设置行为,而不是只能在构造方法中绑定,就可以更灵活的改变鸭子的行为。

    Duck类:

    public abstract class Duck {
        
        FlyBehavior flyBehavior;
        QuackBehavior quackBehavior;
        
        public Duck() {
        }
        
        public void setFlyBehavior(FlyBehavior flyBehavior) {
            this.flyBehavior = flyBehavior;
        }
    
        public void setQuackBehavior(QuackBehavior quackBehavior) {
            this.quackBehavior = quackBehavior;
        }
        
        //......
    }

    新建一个模型鸭类型,默认不会飞

    public class ModelDuck extends Duck {
        public ModelDuck() {
            flyBehavior = new FlyNoWay();
            quackBehavior = new Quack();
        }
        public void display() {
            System.out.println("I am a model duck.");
        }
    }

    然后建立一个火箭动力类(???)

    public class FlyRocketPowered implements FlyBehavior {
        @Override
        public void fly() {
            System.out.println("I am flying with a rocket.");
        }
    }

    通过动态改变行为,模型鸭就可以飞啦~~

    public class MiniDuckSimulator {
        public static void main(String[] args) {
            Duck model = new ModelDuck();
            model.performFly();
            model.setFlyBehavior(new FlyRocketPowered());
            model.performFly();
        }
    }

    输出:

    I can't fly
    I am flying with a rocket.

    把鸭子的行为封装起来,这样可以自由的改变鸭子的行为,也方便对行为的扩展。

    把行为改变为算法,就是策略模式。

    设计原则:多用组合,少用继承。

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

    类图:

    (讲道理我觉得书上这个例子举得一点都不好。。。。)

     一个简单的例子:

    public interface Strategy {
        public int doOperator(int num1, int num2);
    }
    ……………………
    public class AddStrategy implements Strategy {
        @Override
        public int doOperator(int num1, int num2) {
            return num1 + num2;
        }
    }
    ……………………
    public class SubStrategy implements Strategy {
        @Override
        public int doOperator(int num1, int num2) {
            return num1 - num2;
        }
    }
    ……………………
    public class MulStrategy implements Strategy {
        @Override
        public int doOperator(int num1, int num2) {
            return num1 * num2;
        }
    }
    ……………………
    public class Context {
        
        Strategy strategy;
        
        public Context(Strategy strategy) {
            this.strategy = strategy;
        }
        
        public void setStrategy(Strategy strategy) {
            this.strategy = strategy;
        }
        
        public int doOperator(int num1, int num2) {
            return strategy.doOperator(num1, num2);
        }
        
    }

    测试类:

    public class Main {
        public static void main(String[] args) {
            Context context = new Context(new AddStrategy());
            System.out.println(context.doOperator(2, 3));
            context.setStrategy(new SubStrategy());
            System.out.println(context.doOperator(2, 3));
            context.setStrategy(new MulStrategy());
            System.out.println(context.doOperator(2, 3));
        }
    }
    /*
    Output:
    5
    -1
    6
    */
  • 相关阅读:
    2017《Java技术》预备作业 计科1501 杨柳
    Java技术预备作业02 计科1501杨柳
    H2O.ai初步使用
    Vue.Js加入bootstrap及jquery,或加入其他插件vueresource,vuex等
    初次使用git上传代码(转)
    svg绘图工具raphael.js的使用
    EF6添加mysql的edmx实体时报错:无法生成模型:“System.Data.StrongTypingException: 表“TableDetails”中列“IsPrimaryKey”的值为 DBNull
    在window下搭建Vue.Js开发环境
    SQL Server: 索引碎片产生及修复
    Windows注册表(regedit.exe)
  • 原文地址:https://www.cnblogs.com/wenruo/p/6511364.html
Copyright © 2020-2023  润新知