策略模式小试
策略模式是一种非常简单、使用非常广泛的设计模式。
转载请注明出处:http://www.cnblogs.com/zrtqsk/p/3732516.html,谢谢!
一、介绍
看一下《研磨设计模式》里的介绍——定义一系列的算法,把它们一个个封装起来,并且使他们可相互替换。本模式使得算法可独立于使用它的客户而变化。
策略模式的本质是——分离算法、选择实现。
什么意思呢?我们知道什么是算法,简单而言就是计算某种事物的方法。我们都知道排序,最常见的排序包括冒泡排序、快速排序、堆排序、直接插入排序等等很多。这里的排序方法就是算法。每一种排序都有各自不同的特点,适用于不同的情况。如果将这些算法封装起来,以便随时选择切换,这就是策略模式的本质了。
那么怎么实现策略模式呢?说白了就是从众多算法实现中抽象出一个接口,然后众算法都实现这个接口,然后调用者呢,就持有这个接口,于是就可以使用这个算法了。
理解策略模式,可以从“策略”二字着手。什么是策略?就是解决问题的方法、对策!策略模式,就是切换方法的模式!就这么简单。怎么切换方法呢?将方法放进接口,让不同的策略去实现这个接口,然后就可以自由的切换了。
任何的算法实现,我们都可以用策略模式将其包装一下,实现算法的自由切换。
二、结构
Strategy : 策略接口,约束策略算法
Context : 策略上下文,负责与具体的策略类交互
ConcreteStrategy : 具体的策略实现
三、我的实现
假设现在有一个游戏。我们设定正常情况下,玩家获得的游戏分数是固定的。玩家红名时获得分数减半;节假日,所有玩家获得分数翻倍;游戏会员获得分数加成,加成效果与会员等级有关;为了操作方便,还可以指定分数加成值。现在我们把这个分数加成算法包装一下。
1、我们先创建一个分数加成接口,如下:
1 package strategy; 2 3 public interface PointAddition { 4 5 double getAddition(double point); 6 }
2、下面是会员分数加成,与会员等级有关:
1 package strategy; 2 3 public class VipAddition implements PointAddition { 4 5 private int level = 0; 6 7 public VipAddition(int level) 8 { 9 this.level = level; 10 } 11 12 @Override 13 public double getAddition(double point) 14 { 15 return point * (1 + 0.5 +level * 0.05); 16 } 17 18 }
3、玩家红名状态:
1 package strategy; 2 3 //玩家红名时,获得分数减半 4 public class RedNameAddition implements PointAddition { 5 6 @Override 7 public double getAddition(double point) 8 { 9 return point * 3; 10 } 11 }
4、节假日分数加成:
1 package strategy; 2 3 public class FestivalAddition implements PointAddition{ 4 5 @Override 6 public double getAddition(double point) 7 { 8 return point * 2; 9 } 10 }
5、指定分数加成
1 package strategy; 2 3 public class SpecifiedAddition implements PointAddition{ 4 5 private double specifiedAddition = 0; 6 public SpecifiedAddition( double specifiedAddtion) { 7 this.specifiedAddition = specifiedAddition; 8 } 9 10 @Override 11 public double getAddition(double point) 12 { 13 return point * (1 + specifiedAddition); 14 } 15 }
6、由于玩家可能同时处于多种状态,所以各种算法不应单独计算。我们用一个上下文类来处理。如下:
1 package strategy; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 6 public class PointContext { 7 8 //基本分数 9 private double basePoint = 0; 10 //分数折扣 11 private double allDiscount = 0; 12 13 public PointContext(double basePoint) 14 { 15 this.basePoint = basePoint; 16 } 17 18 //所有分数加成的状况 19 private Collection<PointAddition> additions = null; 20 21 //增加分数加成情况 22 public void addPointAddtion(PointAddition add) 23 { 24 if (additions == null) 25 { 26 additions = new ArrayList<PointAddition>(); 27 28 } 29 additions.add(add); 30 } 31 32 //计算总分数 33 public double calculatePoints() 34 { 35 if (additions == null) 36 { 37 allDiscount = 0; 38 } 39 for (PointAddition add : additions) 40 { 41 allDiscount += add.getAddition(1); 42 } 43 return basePoint * allDiscount; 44 } 45 }
7、大功告成!下面来测试一下:
1 package strategy; 2 3 public class Test { 4 5 public static void main(String[] args) 6 { 7 // 节假日分数加成 8 FestivalAddition festivalAdidtion = new FestivalAddition(); 9 // VIP等级为5的分数加成 10 VipAddition vipAddition = new VipAddition(5); 11 // 红名分数减半 12 RedNameAddition redNameAddtion = new RedNameAddition(); 13 // 分数上下文,持有所有的加成状态,并设置基础分为1000 14 PointContext context = new PointContext(1000); 15 // 添加各种加成状态 16 context.addPointAddtion(vipAddition); 17 context.addPointAddtion(festivalAdidtion); 18 context.addPointAddtion(redNameAddtion); 19 // 输出总分数 20 System.out.println("我的总分:" + context.calculatePoints()); 21 } 22 }
结果如下:
我的总分:4250.0
我这里的策略模式是一般策略模式的变种,专门用于这种算法需要叠加的状况。而传统的策略模式仅仅是使某一个算法可以选择替换。
这里需要注意的是这个分数上下文类。计算分数可能有很多种状况,每一种算法需要使用、传入的数据不尽相同。一般为了方便,可以让这个分数上下文类来持有所有的数据,然后算法需要什么就取什么。
侠义的策略模式是算法的切换,而广义的策略模式可以是各种场景、模块的切换。下面我们使用策略模式来讲解一下容错恢复机制。
四、容错恢复机制
什么是容错恢复呢?就是如果程序出错了,程序能够容忍这些错误,用某种方式保证仍然保证程序能够运行下去。
像刚才的算法比较简单,一般不会发生什么异常。我们将它改一下:
1、我们创建一个正常情况下,分数无任何加成的类:
package strategy; public class NomalAddition implements PointAddition { @Override public double getAddition(double point) { return point; } }
2、我们把上下文类PointContext的计算分数的方法改一下,如下:
1 //计算总分数 2 public double calculatePoints() 3 { 4 if (additions == null) 5 { 6 allDiscount = 0; 7 } 8 for (PointAddition add : additions) 9 { try { 10 allDiscount += add.getAddition(1); 11 }catch(Exception e) { 12 //容错恢复 13 allDiscount += new NomalAddition().getAddition(1); 14 } 15 } 16 return basePoint * allDiscount; 17 }
当某个分数加成算法出现异常的时候,用普通的分数加成算法代替。
容错恢复机制不仅可以用于算法,各种模块之间的切换都可以使用,是一种非常实用的异常解决机制。
* ————————如果觉得本博文还行,别忘了推荐一下哦,谢谢!
* 作者:钱书康
* 欢迎转载,请保留此段声明。
* 出处:http://www.cnblogs.com/zrtqsk/
*/