zoukankan      html  css  js  c++  java
  • 设计模式学习笔记之策略模式

    策略模式
        定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
        说明 
        1、可以动态地改变对象的行为;
        2、各个策略算法的平等性,各个策略算法在实现上是相互独立的,相互之间没有任何依赖的(由此,策略模式也可以描述为“策略算法是相同行为的不同实现”);
        3、在运行期间,策略模式在某一时刻,只能使用一个具体的策略算法实现对象,虽然可以动态改变对象行为,但同时只能使用一个;
        4、策略模式可以很简单的扩展新的实现算法。方法:先写一个策略算法来实现新的需求,然后在客户端使用时指定该实现算法即可;
        5、多个if-elseif语句表达的就是一个平等的功能结构,你要么执行if,要不你就执行else,或者是elseif,这个时候,if块里面的实现和else块里面的实现从运行地位上来讲就是平等的。而策略模式就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文来与具体的策略类进行交互。因此多个if-else语句可以考虑使用策略模式。
     
        场景:
        1、报价管理系统中,对于销售部门的人来说,要对不同的客户报不同的价格。如:对于普通用户或者新用户来说,报全价;对老客户报的价格,统一折扣5%;大客户报的价格,统一折扣10%。
        实现:
        A:定义策略接口
        

    /**

     * 策略,定义计算报价算法的接口

     */

    public interface Strategy {

        /**

         * 计算应报的价格

         * @param goodsPrice 商品销售原价

         * @return 计算出来的,应该给客户报的价格

         */

        public double calcPrice(double goodsPrice);

    }

       B:具体实现各个报价标准
        

    /**

     * 具体算法实现,为新客户或者是普通客户计算应报的价格

     */

    public class NormalCustomerStrategy implements Strategy{

        public double calcPrice(double goodsPrice) {

           System.out.println("对于新客户或者是普通客户,没有折扣");

           return goodsPrice;

        }

    }

    /**

     * 具体算法实现,为老客户计算应报的价格

     */

    public class OldCustomerStrategy implements Strategy{

        public double calcPrice(double goodsPrice) {

           System.out.println("对于老客户,统一折扣5%");

           return goodsPrice*(1-0.05);

        }

    }

    /**

     * 具体算法实现,为大客户计算应报的价格

     */

    public class LargeCustomerStrategy implements Strategy{

        public double calcPrice(double goodsPrice) {

           System.out.println("对于大客户,统一折扣10%");

           return goodsPrice*(1-0.1);

        }

    }

        C:价格类,上下文的实现

    /**

     * 价格管理,主要完成计算向客户所报价格的功能

     */

    public class Price {

        /**

         * 持有一个具体的策略对象

         */

        private Strategy strategy = null;

        /**

         * 构造方法,传入一个具体的策略对象

         * @param aStrategy 具体的策略对象

         */

        public Price(Strategy aStrategy){

           this.strategy = aStrategy;

        }  

        /**

         * 报价,计算对客户的报价

         * @param goodsPrice 商品销售原价

         * @return 计算出来的,应该给客户报的价格

         */

        public double quote(double goodsPrice){

           return this.strategy.calcPrice(goodsPrice);

        }

    }

        D:写个客户端进行测试

    public class Client {

        public static void main(String[] args) {

           //1:选择并创建需要使用的策略对象

           Strategy strategy = new LargeCustomerStrategy ();

           //2:创建上下文

           Price ctx = new Price(strategy);

           //3:计算报价

           double quote = ctx.quote(1000);

           System.out.println("向客户报价:"+quote);

        }

    }

        2、容错恢复机制。程序运行的时候,正常情况下应该按照某种方式来做,如果按照某种方式来做发生错误的话,系统并不会崩溃,也不会就此不能继续向下运行了,而是有容忍出错的能力,不但能容忍程序运行出现错误,还提供出现错误后的备用方案,也就是恢复机制,来代替正常执行的功能,使程序继续向下运行。
        比如在一个系统中,所有对系统的操作都要有日志记录,而且这个日志还需要有管理界面,这种情况下通常会把日志记录在数据库里面,方便后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面,然后在合适的时候把文件中的记录再转录到数据库中。
        可以采用策略模式,把日志记录到数据库和日志记录到文件当作两种记录日志的策略,然后在运行期间根据需要进行动态的切换。
        (1)先定义日志策略接口,很简单,就是一个记录日志的方法,示例代码如下:

    /**

     * 日志记录策略的接口

     */

    public interface LogStrategy {

        /**

         * 记录日志

         * @param msg 需记录的日志信息

         */

        public void log(String msg);

    }

        (2)实现日志策略接口,先实现默认的数据库实现,假设如果日志的长度超过长度就出错,制造错误的是一个最常见的运行期错误,示例代码如下:

    /**

     * 把日志记录到数据库

     */

    public class DbLog implements LogStrategy{

        public void log(String msg) {     

           //制造错误

           if(msg!=null && msg.trim().length()>5){

               int a = 5/0;

           }

           System.out.println("现在把 '"+msg+"' 记录到数据库中");

        }

    }

        接下来实现记录日志到文件中去,示例代码如下: 

    /**

     * 把日志记录到文件

     */

    public class FileLog implements LogStrategy{

        public void log(String msg) {

           System.out.println("现在把 '"+msg+"' 记录到文件中");

        }

    }

        (3)接下来定义使用这些策略的上下文,注意这次是在上下文里面实现具体策略算法的选择,所以不需要客户端来指定具体的策略算法了,示例代码如下:

        (4)看看现在的客户端,没有了选择具体实现策略算法的工作,变得非常简单,故意多调用一次,可以看出不同的效果,示例代码如下:

     
     
    参考资料:《Head First 设计模式》
                  http://www.uml.org.cn/sjms/201009092.asp  
  • 相关阅读:
    【Lua】LuaForWindows_v5.1.4-46安装失败解决方案
    【C++】指针引发的bug
    【C++】指针引发的bug
    【C++】位操作(3)-获取某位的值
    bzoj1444
    bzoj1758
    bzoj3091
    poj1741 bzoj2152
    bzoj2125 3047
    bzoj3669
  • 原文地址:https://www.cnblogs.com/LeslieXia/p/5494856.html
Copyright © 2011-2022 走看看