zoukankan      html  css  js  c++  java
  • 策略模式

    策略模式本质

      分离算法,选择实现

    对设计原理的实现

      从设计原则上来看,策略模式很好地体现了开-闭原则。通过把一系列可变的算法进行封装,并定义出合理的使用结构,使得在系统出现新算法时,额能很容易的把算法加入到已有的系统中,而已有的实现不需要做任何更改。

    何时选择策略模式

    1. 出现许多相关的类,仅仅是行为有差别的情况下,可以使用策略模式来使用多个行为中的一个配置一个类的方法,实现算法动态切换。
    2. 出现同一个算法,有很多不同实现的情况下,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次。
    3. 需要封装算法中,有与算法相关数据的情况下,可以使用策略模式避免暴露这些跟算法相关的数据结构。
    4. 出现抽象一个定义了很多行为的类,并且是通过多个if-else语句来选择这些行为的情况下,可以使用策略模式来代替这些条件语句。

    优缺点

      优点:

    1. 定义一系列算法
    2. 避免多重条件语句
    3. 更好的扩展性

      缺点

    1. 客户必须了解每种策略的不同
    2. 怎讲对象数目
    3. 只适合扁平的算法结构(一系列算法的地位是平等的,是可以相互替换的,在运行时刻只有一个算法被使用,限制了算法的使用层级,使用的时候不能嵌套使用)

    示例:工资支付的实现思路

      功能:工资支付方式的问题。很多企业的工资支付方式是很灵活的,可支付的方式是很多的,比如:人民币现金支付、美元现金支付、银行转账到工资账号、银行转账到工资卡,甚至可能工资转股权等方式。

      要实现这样的功能,策略模式是一个很好的选择,在实现这个功能时,不同的策略算法需要的数据是不一样的,如:现金支付就不需要银行账号,而银行转账就需要账号。这就导致在设计策略接口中的方法时,不太好确定参数的个数,而且,就算现在吧所有参数都列上了,今后扩展呢?难道再来修改策略接口吗?那到底如何实现才能扩展时最方便呢?

      解决方案一:就是把上下文(context)当作参数传递给策略对象。这样,如果要扩展新的策略实现,只需要扩展上下文就可以了,已有的实现不需要做任何更改。

      实现代码:

        /**

        * 支付工资的策略接口,公司有多种支付工资的算法

        * 比如:现金,银行卡,美元支付等

        **/

        public interface PaymentStrategy{

          //公司给某人真正支付工资

          //@param ctx 支付工资的上下文,里面包含算法需要的数据

          public void pay(PaymentContext ctx);

     

        }

     

        //人民币现金支付

        public class RMBCash implements PaymentStrategy{

          public void pay(PaymentContext  ctx){

            System.out.println("现金给"+ctx.getUserName()+"人民币现金支付"+ctx.getMoney()+"元");

          }

        }

        //美元现金支付

        public class DollarCash implements PaymentStrategy{

          public void pay(PaymentContext  ctx){

            System.out.println("现金给"+ctx.getUserName()+"美元现金支付"+ctx.getMoney()+"元");

          }

        }

        //支付工资的上下文,每个人的工资不同,支付方式也不同

        public class PaymentContext{

          private String userName = null;

          private double money = 0.0;

          //支付工资的方式的策略接口

          private PaymentStrategy strategy = null;

          //构造函数,传入被支付工资的人员,应支付的金额和具体的支付策略

          //userName 被支付工资的人员  money 应支付的金额  strategy 具体的支付策略

          public PaymentContext (String userName, double money, PaymentStrategy strategy){

            this.userName = userName;

            this.money = money;

            this.strategy = strategy;

          }

          //省略get方法,只有get方法,让策略算法在实现的时候,根据需要来获取上下文的数据

          //立即支付工资

          public void payNow(){

            //使用客户希望的支付策略来支付工资

            this.strategy.pay(this);

          }

        }

        //客户端

        public class Client{

          public static void main(String[] agrs){

          //创建相应的支付策略

          PaymentStrategy strategyRMB = new RMBCash();

          PaymentStrategy strategyDollar = new DollarCash();

          //准备小李的支付工资上下文

          PaymentContext ctx1 = new PaymentContext ("小李",5000,strategyRMB);

          //向小李支付工资

          ctx1.payNow();

          //切换一个人,给petter支付工资

          PaymentContext ctx2 = new PaymentContext ("petter",8000,strategyDollar);

          ctx2.payNow();

        }

        }

        

        扩展示例

        现在我们要加一种支付方式,要求能支付到银行卡

        代码示例:

        //扩展的支付上下文对象

        public class PaymentContext2 extends PaymentContext{

          //银行账号

          private String account = null;

          //构造函数

          public PaymentContext2 (String userName, double money, String account, PaymentStrategy strategy){

            super(userName,money, strategy);

            this.account = account;

          }

          public String getAccount(){return account;}

        }

        public class Card implements PaymentStrategy{

          public void pay(PaymentContext ctx){

            PaymentContext2 ctx2 = (PaymentContext2)ctx;

            System.out.println("现在给"+ctx2.getUserName()+"的"+ctx2.getAccount()+"账号支付了"+ctx.getMoney()+"元");

          }

        }

        public class Client {

          public static void main(String[] agrs){

            PaymentStrategy strategyCard = new Card();

            PaymenttContext ctx= new PaymentContext2("小王",9000,"00121113",strategyCard);

            ctx.payNow();

          }

        }

        另一种扩展方式

        上面那种方式是通过上下文对象来准备新的算法需要的数据,还有一种就是通过策略的构造函数来传入新算法需要的数据,这样实现就不需要扩展上下文了,直接添加一个新的算法实现就可以了。

        代码示例:

        public class Card2 impements PaymentStrategy{

          //账号信息

          private String account = "";

          //构造函数

          public Card2(String account){

            this.account = account;

          }

          public void pay(PaymentContex ctx){

            System.out.println("现在给"+ctx2.getUserName()+"的"+ctx2.getAccount()+"账号支付了"+ctx.getMoney()+"元");

          }

        } 

        两种实现扩展方式的比较:

          对与扩展上下文的方式

            优点:

        1. 这样实现,使所有策略的风格更统一;
        2. 在上下文添加的数据可以视为公共数据,别的相应算法也能用上;

            缺点:

              1. 如果这些数据只是用于特定的算法,这样数据就有点浪费;

              2. 每次添加新的算法都去扩展上下文,容易造成复杂的上下文对象层次;

          对与在策略算法的实现上添加自己需要的数据方式

            优点:

              1. 实现简单

            缺点:

              1. 和其他策略算法的实现方式不一样

              2. 外部使用这个策略算法的时候也不一样,难以以一个统一的方式来动态切换策略算法。

  • 相关阅读:
    设计者模式详解--代理模式
    设计者模式详解--适配器模式
    设计者模式详解--原型模式
    设计者模式详解--建造者模式
    设计者模式详解--单例模式
    设计者模式详解--抽象工厂模式
    设计者模式详解--工厂方法模式
    angularjs 选项卡 --- 自定义属性
    AngularJS 自定义指令
    Jquery中的prop()方法 全选或全不选
  • 原文地址:https://www.cnblogs.com/johnnyC/p/9513278.html
Copyright © 2011-2022 走看看