zoukankan      html  css  js  c++  java
  • 模式的秘密-策略模式

    策略模式

    策略模式将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现,

    并使得他们可以相互替换,从而导致客户端程序独立于算法的改变

    实例:

    假如有一个鸭子类:鸭子有叫的功能,有展示功能,另外需要给鸭子加一个飞行能力,让鸭子飞起来,但是对于不同的鸭子有不同的飞行能力,

    比如有的展翅高飞,有的不会飞,有的飞向太空。

    方案一:继承:

    在父类中提供实现方法,子类通过继承获得父类中的飞行行为。

    优点:简单易用,已有应用可以快速添加飞行能力。

    缺点:不具有灵活性,对未来变更支持性差。假如子类鸭子有跟父类不一样的飞行方法,需要在子类中复写飞行的方法以提供新的

    飞行行为,这很容易出差造成错误(粗心的程序员忘记复写),假如一只大黄鸭,是不具备飞行能力的,但是因为程序员忘记复写飞行,导致该大黄鸭能飞。

    方案二:抽象方法

    在父类中提供抽象方法,强迫子类实现自己的飞行行为。

    优点:足够灵活,小伙伴再也不会忘记复写代码了,大黄鸭也不会飞到天上吓你了。

    缺点:累死小伙伴,每个子类都要实现一遍代码,即使是相同的行为也不例外。

      代码重复,却没有复用代码。万一再有一个bug,哎妈呀,不敢想

    继承是重用代码的利器,但是继承并不总是最好的工具。

    解决思想:复合优先于继承,多用组合,少用继承。

    组合:在类中增加一个私有域,引用另一个已有的类的实例,通过调用引用实例的方法从而获得新的功能,

    这种设计被称为组合(复用)。

    就像赛车通过换轮胎,获得超凡奔跑能力。

    方案三:组合

    将飞行行为抽象为接口,在父类中持有该接口,并由该接口代理飞行行为。

    public interface  FlyingStragety
    {
         void performFly();      
    }

    父类:

    private FlyingStragety  flyingStragety;
    public void fly()
    {
         flyingStragety.performFly();
    }

    优点:足够灵活,复用代码,更易于维护。

    策略模式的设计原则:

    1,找出应用中需要变化的部分,把他们独立出来,不要和那些不需要的代码混在一起(可复用的功能独立出来,供不同的子类重用,这也是为什么不采用抽象的原因

    2,面向接口编程,而不是面向实现编程。

    3,多用组合,少用继承。

    策略模式的实现:

    1,通过分离变化得出的策略接口Stratege。(策略接口,实现鸭子的飞行行为)。

    2,继承策略模式接口,实现Stratege的实现类(不同的飞行行为,分别实现实现类)。

    3,策略模式的实现:客户程序有一个"Stratege接口对象"。(在父类抽象类中实现即可)

    4,在客户程序中选择/组装正确的Stratege实现。(在stratege对象的set方法里面,传入要选择的具体策略类实例)。

    具体代码:

    1,先定义一个飞行策略接口,该接口提供一个飞行方法。

    package com.Stratege;
    
    /*
     * 策略接口,实现鸭子的飞行行为
     * */
    public interface FlyingStragety {
    
        void performFly();
    }

    2,对于飞行接口,分别提供几种飞行实现类,来供客户程序选择使用哪个策略Stratege实现。

    如:不会飞实现类:

    package com.Stratege.impl;
    
    import com.Stratege.FlyingStragety;
    //不能飞行
    public class FlyNoWay implements FlyingStragety {
    
        @Override
        public void performFly() {
            System.out.println("我不会飞行,有点羞涩");
        }
    }

    展翅高飞实现类:

    package com.Stratege.impl;
    
    import com.Stratege.FlyingStragety;
    //第一种飞行策略:展翅高飞
    public class FlyWithMe implements FlyingStragety {
    
        @Override
        public void performFly() {
            System.out.println("振翅高飞");
        }
    }

    3,不同的飞行策略的接口和实现类已经实现了。

    现在开始实现客户端类,假如有三种鸟:绿头鸭,红头鸭,橡胶鸭,小黄鸭。其中绿头鸟和红头鸭会飞,

    橡胶鸭和小黄鸭不会飞,橡皮鸭子叫声有点沙哑:嘎~嘎~嘎~。

    4,定义一个会叫,能展示的鸭子,不同的鸭子展示方式不一样,这里通过一个抽象方法实现,并且采用策略模式提供飞行功能。

    策略模式飞行:1,提供策略模式飞行接口对象,2,提供该接口对象的set方法。

           3,提供飞行方法,方法里面由策略模式接口对象调用自身的performFly。这样实现了,不同的子类,调用飞行方法,不需要修改飞行方法,

           只需要为给策略模式飞行接口对象实例化不同的策略模式实现类。

    package com.Stratege;
    
    /*
     * 超类,所有的鸭子都要继承此类
     * 抽象了鸭子的行为:显示和叫
     * */
    public abstract class Duck {
        
        //鸭子发出叫声
        //通用行为,由超类实现
        public void quack()
        {
            System.out.println("嘎嘎嘎");
        }
        
        //显示鸭子的外观,鸭子外观各不相同,声明为abstract,由子类实现
        public abstract void display();
        
        private FlyingStragety flyingStragety;
        
        public void setFlyingStragety(FlyingStragety flyingStragety) {
            this.flyingStragety = flyingStragety;
        }
        //调用策略接口实现飞行
        public void fly()
        {
            this.flyingStragety.performFly();
        }
    
    }

    5,不同的鸭子子类分别实例化:在构造方法里面,调用父类的setStragety方法,方法的参数传递对应的实现子类实例,从而实现往子类中注入不同的策略实例,

    绿鸭:

    package com.Stratege;
    
    import com.Stratege.impl.FlyWithMe;
    
    public class MallardDuck extends Duck {
    
        public MallardDuck()
        {
            super();
            //给红头鸭提供了一个翅膀飞行的能力
            super.setFlyingStragety(new FlyWithMe());
        }
    
        @Override
        public void display() {
            System.out.println("我的头是绿色的");
        }
    }

    红头鸭:

    package com.Stratege;
    
    import com.Stratege.impl.FlyWithMe;
    
    public class RedheadDuck extends Duck {
        
        public RedheadDuck()
        {
            super();
            //给红头鸭提供了一个翅膀飞行的能力
            super.setFlyingStragety(new FlyWithMe());
        }
    
        @Override
        public void display() {
            System.out.println("我的头是红色的");
        }
    
    }

    橡胶鸭:因为叫声不一样,重写了叫声方法。

    package com.Stratege;
    
    import com.Stratege.impl.FlyNoWay;
    
    public class RubberDuck extends Duck{
    
        public RubberDuck()
        {
            super();
            //给红头鸭提供了一个翅膀飞行的能力
            super.setFlyingStragety(new FlyNoWay());
        }
    
        @Override
        public void display() {
            System.out.println("我全身发黄,嘴巴很红");
        }
        
        public void quack()
        {
            System.out.println("嘎~嘎~嘎~");
        }
    }

    大黄鸭:不会飞。

    package com.Stratege;
    
    import com.Stratege.impl.FlyNoWay;
    
    public class BigYellow extends Duck {
    
        public BigYellow()
        {
            super();
            //给红头鸭提供了一个翅膀飞行的能力
            super.setFlyingStragety(new FlyNoWay());
        }
    
        @Override
        public void display() {
            System.out.println("我身体很大,全身黄黄");
        }
    }

    测试:

    package com.Stratege;
    
    public class DuckTest {
    
        public static void main(String[] args) {
    
            System.out.println("测试鸭子程序");
            System.out.println("-----------------");
            Duck duck=new MallardDuck();
            
            duck.display();
            duck.quack();
            duck.fly();
            
            System.out.println("-----------------");
            
            Duck duck2=new RedheadDuck();
            duck2.display();
            duck2.quack();
            duck2.fly();
            
            System.out.println("-----------------");
            
            Duck duck3=new RubberDuck();
            duck3.display();
            duck3.quack();
            duck3.fly();
            
            System.out.println("-----------------");
            
            Duck duck4=new BigYellow();
            duck4.display();
            duck4.quack();
            duck4.fly();        
            
        }
    
    }

    运行结果:

    测试鸭子程序
    -----------------
    我的头是绿色的
    嘎嘎嘎
    振翅高飞
    -----------------
    我的头是红色的
    嘎嘎嘎
    振翅高飞
    -----------------
    我全身发黄,嘴巴很红
    嘎~嘎~嘎~
    我不会飞行,有点羞涩
    -----------------
    我身体很大,全身黄黄
    嘎嘎嘎
    我不会飞行,有点羞涩

    总结:

    策略模式的优点:

    1,使用了组合模式,使得架构更加灵活。

    2,富有弹性,可以较好的应对变化(开-闭原则)。

    3,更好的代码复用性。(相对于继承。而且如果相同的策略,只需要实例化对应的策略模式类就行了)

    4,消除大量的条件语句。(不同的子类,当对于不同的策略,只需要为策略接口对象,实例化对应的策略模式类就行了)

    适用场景:

    1,许多相关的类,仅仅是行为差异。

    2,运行时选取不同的算法变体。

    3,通过条件语句在多个分支中选取一。

  • 相关阅读:
    MetaMask/metamask-extension-provider
    MetaMask/json-rpc-engine
    MetaMask/json-rpc-middleware-stream
    DamonOehlman/detect-browser
    kumavis/obj-multiplex
    java面试第三天
    java面试第二天
    JavaScript公共函数
    Eclipse快捷键大全
    Jdbc入门
  • 原文地址:https://www.cnblogs.com/alsf/p/8956075.html
Copyright © 2011-2022 走看看