`
chjavach
  • 浏览: 461317 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

研磨设计模式之策略模式-1

阅读更多

 

 

首先感谢众多朋友的支持、评论和鼓励,只有多多努力,写点好的博文来回报大家的好意!

 

接下来想写写另外一个虽然较简单,但是使用很频繁的模式——策略模式

 

策略模式(Strategy)

1  场景问题

1.1  报价管理

        向客户报价,对于销售部门的人来讲,这是一个非常重大、非常复杂的问题,对不同的客户要报不同的价格,比如:

  • 对普通客户或者是新客户报的是全价
  • 对老客户报的价格,根据客户年限,给予一定的折扣
  • 对大客户报的价格,根据大客户的累计消费金额,给予一定的折扣
  • 还要考虑客户购买的数量和金额,比如:虽然是新用户,但是一次购买的数量非常大,或者是总金额非常高,也会有一定的折扣
  • 还有,报价人员的职务高低,也决定了他是否有权限对价格进行一定的浮动折扣

        甚至在不同的阶段,对客户的报价也不同,一般情况是刚开始比较高,越接近成交阶段,报价越趋于合理。
        总之,向客户报价是非常复杂的,因此在一些CRM(客户关系管理)的系统中,会有一个单独的报价管理模块,来处理复杂的报价功能。
        为了演示的简洁性,假定现在需要实现一个简化的报价管理,实现如下的功能:
           (1)对普通客户或者是新客户报全价
           (2)对老客户报的价格,统一折扣5%
           (3)对大客户报的价格,统一折扣10%
        该怎么实现呢?


1.2  不用模式的解决方案

        要实现对不同的人员报不同的价格的功能,无外乎就是判断起来麻烦点,也不多难,很快就有朋友能写出如下的实现代码,示例代码如下:

 

 

/**

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

 */

public class Price {

    /**

     * 报价,对不同类型的,计算不同的价格

     * @param goodsPrice 商品销售原价

     * @param customerType 客户类型

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

     */

    public double quote(double goodsPrice,String customerType){

       if(customerType.equals("普通客户")){

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

           return goodsPrice;

       }else if(customerType.equals("老客户")){

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

           return goodsPrice*(1-0.05);

       }else if(customerType.equals("大客户")){

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

           return goodsPrice*(1-0.1);        

       }

       //其余人员都是报原价

       return goodsPrice;

    }

}

 

1.3  有何问题

        上面的写法是很简单的,也很容易想,但是仔细想想,这样实现,问题可不小,比如:

  • 第一个问题:价格类包含了所有计算报价的算法,使得价格类,尤其是报价这个方法比较庞杂,难以维护。

        有朋友可能会想,这很简单嘛,把这些算法从报价方法里面拿出去,形成独立的方法不就可以解决这个问题了吗?据此写出如下的实现代码,示例代码如下:

 

 

/**

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

 */

public class Price {

    /**

     * 报价,对不同类型的,计算不同的价格

     * @param goodsPrice 商品销售原价

     * @param customerType 客户类型

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

     */

    public double quote(double goodsPrice,String customerType){

       if(customerType.equals("普通客户")){

           return this.calcPriceForNormal(goodsPrice);

       }else if(customerType.equals("老客户")){

           return this.calcPriceForOld(goodsPrice);

       }else if(customerType.equals("大客户")){

           return this.calcPriceForLarge(goodsPrice);       

       }

       //其余人员都是报原价

       return goodsPrice;

    }

    /**

     * 为新客户或者是普通客户计算应报的价格

     * @param goodsPrice 商品销售原价

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

     */

    private double calcPriceForNormal(double goodsPrice){

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

       return goodsPrice;

    }

    /**

     * 为老客户计算应报的价格

     * @param goodsPrice 商品销售原价

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

     */

    private double calcPriceForOld(double goodsPrice){

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

       return goodsPrice*(1-0.05);

    }

    /**

     * 为大客户计算应报的价格

     * @param goodsPrice 商品销售原价

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

     */

    private double calcPriceForLarge(double goodsPrice){

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

       return goodsPrice*(1-0.1); 

    }

}

 

        这样看起来,比刚开始稍稍好点,计算报价的方法会稍稍简单一点,这样维护起来也稍好一些,某个算法发生了变化,直接修改相应的私有方法就可以了。扩展起来也容易一点,比如要增加一个“战略合作客户”的类型,报价为直接8折,就只需要在价格类里面新增加一个私有的方法来计算新的价格,然后在计算报价的方法里面新添一个else-if即可。看起来似乎很不错了。
        真的很不错了吗?
        再想想,问题还是存在,只不过从计算报价的方法挪动到价格类里面了,假如有100个或者更多这样的计算方式,这会让这个价格类非常庞大,难以维护。而且,维护和扩展都需要去修改已有的代码,这是很不好的,违反了开-闭原则。

 

  • 第二个问题:经常会有这样的需要,在不同的时候,要使用不同的计算方式。

        比如:在公司周年庆的时候,所有的客户额外增加3%的折扣;在换季促销的时候,普通客户是额外增加折扣2%,老客户是额外增加折扣3%,大客户是额外增加折扣5%。这意味着计算报价的方式会经常被修改,或者被切换。
        通常情况下应该是被切换,因为过了促销时间,又还回到正常的价格体系上来了。而现在的价格类中计算报价的方法,是固定调用各种计算方式,这使得切换调用不同的计算方式很麻烦,每次都需要修改if-else里面的调用代码。
        看到这里,可能有朋友会想,那么到底应该如何实现,才能够让价格类中的计算报价的算法,能很容易的实现可维护、可扩展,又能动态的切换变化呢?

 

 

 

《研磨设计模式》一书已经上市,卓越网销售链接:
http://www.amazon.cn/%E7%A0%94%E7%A3%A8%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E9%99%88%E8%87%A3/dp/B004G8P90S/ref=sr_1_1?ie=UTF8&qid=1295358211&sr=8-1

 

也可以直接在卓越网上搜索《研磨设计模式》

 

当当网的销售链接:http://product.dangdang.com/product.aspx?product_id=20994349&ref=search-0-mix

 

 

希望朋友们能给本书评评分,写点评论,多谢大家的支持!

 

 

未完待续......
 

 

 

99
5
分享到:
评论
10 楼 zuishengmengsi1990 2012-03-12  
 
9 楼 hxtoyou 2011-03-21  
为什么我没看到interface?皇帝的新衣?
8 楼 chjavach 2010-07-16  
rather_lonely 写道
LZ用实例来描述真是即生动又好理解,有个小小的不是设计模式问题,
customerType.equals("普通客户")改成这种写法("普通客户".equals(customerType))是否会更好点,可以防止空指针出现


谢谢你,你真是细致,呵呵,你说的问题改过来会更好,写代码的时候,较为随意了.
7 楼 rather_lonely 2010-07-15  
LZ用实例来描述真是即生动又好理解,有个小小的不是设计模式问题,
customerType.equals("普通客户")改成这种写法("普通客户".equals(customerType))是否会更好点,可以防止空指针出现
6 楼 chjavach 2010-07-01  
to  guzhan 兄:
    策略模式的实现中,存在一个由谁来选择策略的问题,一种方式就是由客户端来选择并创建具体的策略对象。而这整个策略模式的实现,就把那个if...else消除掉了。
    if..else不就是两个部分嘛:一是选择分支,二是执行功能。在改造成策略模式过后,选择部分就放到客户端去完成了,而具体的功能实现放到每个策略是先里面了。这不就把if..else用策略模式来消除了吗
5 楼 guzhan 2010-06-28  
请教一下楼主,刚开始引入问题时,采用if...else..来获取应该使用何种价格方式
引用

if(customerType.equals("普通客户")){
           System.out.println("对于新客户或者是普通客户,没有折扣");
           return goodsPrice;
       }else if(customerType.equals("老客户")){
           System.out.println("对于老客户,统一折扣5%");
           return goodsPrice*(1-0.05);
       }else if(customerType.equals("大客户")){
           System.out.println("对于大客户,统一折扣10%");
           return goodsPrice*(1-0.1);     
       }
       //其余人员都是报原价
       return goodsPrice;

而后期的代码中则表示
引用

先是客户端来选择并创建具体的策略对象

那实际上,后期的代码一开始就已知了采用何种价格方式,也就是说策略模式不是用来消除这个if...else...的判断吗?
所以对于楼主的开始的问题与后面的解决方案是否不一致呢?
4 楼 fly_jj 2010-06-24  
interface~~ !!
温故而知新。
感谢楼主
期待楼主的下回分解。
3 楼 shenmifeidie 2010-06-23  
哈哈,我也是从工厂方法模式追着看过来的,楼上的兄弟握手
2 楼 ilovehome 2010-06-23  
从工厂方法模式看过来,博主写得真好.
通过实际的案例来引入策略模式,强烈支持
1 楼 raojl 2010-06-23  
绝对支持,比听群众小说还有趣!

相关推荐

    研磨设计模式(完整带书签).part2.pdf

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式(完整带书签).part1.pdf

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式--chjavach的博客文章

    单例模式、工厂方法模式、策略模式、命令模式和桥接模式。

    研磨设计模式-part2

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式-part4

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式-part3

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式.part1(共4个)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式.docx

    研磨设计模式系列,包括: 单例模式、工厂方法模式、策略模式、命令模式和桥接模式

    研磨设计模式.part3(共4个)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式.part2(共4个)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式.part4(共4个)

    《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,...

    研磨设计模式之策略模式

     接下来想写写另外一个虽然较简单,但是使用很频繁的模式——策略模式策略模式(Strategy)1 场景问题1.1 报价管理向客户报价,对于销售部门的人来讲,这是一个非常重大、非常复杂的问题,对不同的客户要报不同的...

    研磨策略模式

    在网上搜到的资源,很详细的介绍了最常用最简单的设计模式--策略模式

Global site tag (gtag.js) - Google Analytics