Chinaunix首页 | 论坛 | 博客
  • 博客访问: 337292
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1134
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-25 09:41
个人简介

目前任职于搜狐~

文章分类

全部博文(31)

文章存档

2014年(12)

2013年(19)

分类: Java

2014-02-11 21:57:17

策略模式是面向对象行为模式中的一种简单常用的设计模式。
首先看下GOF对策略模式的定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
策略模式的应用场景描述:
(1)实现某特定功能在不同的情况下采用不同的策略即算法,程序在运行时动态选择所要采用的策略。
(2)对客户端完全隐藏算法的具体实现细节。
(3)不同种算法之间可以彼此替换且完全独立。
策略模式的三种角色:
(1)抽象策略角色:通常由一个接口或者抽象类实现。
(2)具体策略角色:即包含具体策略的实现算法的类,程序中可能不止一个具体策略的角色,多个角色彼此独立。具体策略角色实现了抽象策略角色接口。
(3)环境角色:包含一个抽象策略角色的引用,通过set方法或构造方法完成策略对象的赋值,并提供给客户端一个策略调用的方法。

下面以超市打折促销的例子为大家描述下策略模式的具体使用方法。
超市打折促销有以下几种方式:
(1)对普通会员是商品原价。
(2)对中级会员是商品原价的85折。
(3)对高级会员是商品原价的75折。

了解了功能需求之后,用策略模式如何实现功能呢?下面给大家贴上范例代码。


1、第一个文件:价格计算抽象策略接口(ICalculationPriceStrategy.java)

点击(此处)折叠或打开

  1. /**
  2.  * 价格计算策略接口
  3.  *
  4.  */
  5. public interface ICalculationPriceStrategy {

  6.     /**
  7.      * 价格计算方法
  8.      * @return
  9.      */
  10.     public double calculationPrice(double price);
  11. }
2、第二个文件:普通会员价格计算的策略实现类(OrdinaryMemberStrategy.java)

点击(此处)折叠或打开

  1. /**
  2.  * 普通会员价格计算策略实现类
  3.  */
  4. public class OrdinaryMemberStrategy implements ICalculationPriceStrategy {

  5.     @Override
  6.     public double calculationPrice(double price) {
  7.         System.out.println("--采用普通会员价格计算策略--");
  8.         return price;
  9.     }
  10. }
3、第三个文件:中级会员价格计算的策略实现类(IntermediateMemberStrategy.java)

点击(此处)折叠或打开

  1. /**
  2.  * 中级会员价格计算策略实现类
  3.  */
  4. public class IntermediateMemberStrategy implements ICalculationPriceStrategy {

  5.     @Override
  6.     public double calculationPrice(double price) {
  7.         System.out.println("--采用中级会员价格计算策略--");
  8.         return price * 0.85;
  9.     }

  10. }
4、第四个文件:高级会员价格计算的策略实现类(SeniorMemberStrategy.java)

点击(此处)折叠或打开

  1. /**
  2.  * 高级会员价格计算策略实现类
  3.  */
  4. public class SeniorMemberStrategy implements ICalculationPriceStrategy {

  5.     @Override
  6.     public double calculationPrice(double price) {
  7.         System.out.println("--采用高级会员价格计算策略--");
  8.         return price * 0.75;
  9.     }

  10. }

5、第五个文件:环境角色(CalcPriceContext.java)

点击(此处)折叠或打开

  1. /**
  2.  * 价格计算环境角色对象
  3.  */
  4. public class CalcPriceContext {

  5.     private ICalculationPriceStrategy calcPriceStrategy;
  6.     
  7.     public CalcPriceContext(ICalculationPriceStrategy calcPriceStrategy){
  8.         this.calcPriceStrategy = calcPriceStrategy;
  9.     }
  10.     
  11.     public double calculationPrice(double price){
  12.         double finalPrice = 0;
  13.         if(calcPriceStrategy != null){
  14.             finalPrice = calcPriceStrategy.calculationPrice(price);
  15.         }
  16.         return finalPrice;
  17.     }
  18. }
6、第六个文件:客户端测试方法(TestMain.java)

点击(此处)折叠或打开

  1. public class TestMain {

  2.     public static void main(String [] args){
  3.         double price = 368;
  4.         double finalPrice = 0;
  5.         CalcPriceContext context = null;
  6.         context = new CalcPriceContext(new OrdinaryMemberStrategy());
  7.         finalPrice = context.calculationPrice(price);
  8.         System.out.println("普通会员价格为:" + finalPrice);
  9.         context = new CalcPriceContext(new IntermediateMemberStrategy());
  10.         finalPrice = context.calculationPrice(price);
  11.         System.out.println("中级会员价格为:" + finalPrice);
  12.         context = new CalcPriceContext(new SeniorMemberStrategy());
  13.         finalPrice = context.calculationPrice(price);
  14.         System.out.println("高级会员价格为:" + finalPrice);
  15.     }
  16. }
看了上面的策略模式实现,让我们分析下策略模式的优点,首先考虑个问题如果以上功能不用策略模式实现,那我们的代码会是什么样子的呢?

点击(此处)折叠或打开

  1. public class CalcPriceMain {

  2.     public static void main(String [] args){
  3.         double price = 368;
  4.         double finalPrice = 0;
  5.         CalcPriceMain calcPriceMain = new CalcPriceMain();
  6.         finalPrice = calcPriceMain.calculationPrice("ordinary",price);
  7.         System.out.println("普通会员价格为:" + finalPrice);
  8.         finalPrice = calcPriceMain.calculationPrice("intermediate",price);
  9.         System.out.println("中级会员价格为:" + finalPrice);
  10.         finalPrice = calcPriceMain.calculationPrice("senior",price);
  11.         System.out.println("高级会员价格为:" + finalPrice);
  12.     }
  13.     
  14.     /**
  15.      * 价格计算逻辑处理
  16.      * @param memberType
  17.      * @param price
  18.      * @return
  19.      */
  20.     public double calculationPrice(String memberType,double price){
  21.         if("ordinary".equals(memberType)){
  22.             return calcPriceForOrdinaryMember(price);
  23.         }else if("intermediate".equals(memberType)){
  24.             return calcPriceForIntermediateMember(price);
  25.         }else if("senior".equals(memberType)){
  26.             return calcPriceForSeniorMember(price);
  27.         }
  28.         return 0;
  29.     }
  30.     
  31.     /**
  32.      * 普通会员价格计算实现方法
  33.      * @param price
  34.      * @return
  35.      */
  36.     public double calcPriceForOrdinaryMember(double price){
  37.         return price;
  38.     }
  39.     
  40.     /**
  41.      * 中级会员价格计算实现方法
  42.      * @param price
  43.      * @return
  44.      */
  45.     public double calcPriceForIntermediateMember(double price){
  46.         return price * 0.85;
  47.     }
  48.     
  49.     /**
  50.      * 高级会员价格计算实现方法
  51.      * @param price
  52.      * @return
  53.      */
  54.     public double calcPriceForSeniorMember(double price){
  55.         return price * 0.75;
  56.     }
  57.     
  58. }

代码对比可以知道传统的实现方式,将各种策略的实现全都耦合在一起非常不利于代码的扩展,如果要额外新增新的策略,则要更改现在的代码结构违背了程序设计的开闭原则。
策略模式的优点如下:
(1)策略模式提供了管理相关的算法族的方法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面不利于代码的扩展。
(3)修改具体策略不影响客户端的调用。
策略模式的缺点如下:
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,所以会增加系统需要维护的类的数量。
(3)在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。这本身没有解除客户端需要选择判断的压力,而策略 模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。
 

阅读(6406) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~