策略模式小试

策略模式是一种非常简单、使用非常广泛的设计模式。

转载请注明出处: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     }

当某个分数加成算法出现异常的时候,用普通的分数加成算法代替。

容错恢复机制不仅可以用于算法,各种模块之间的切换都可以使用,是一种非常实用的异常解决机制。

 

 

 

 

posted @ 2014-05-16 16:51  Chandler Qian  阅读(1708)  评论(0编辑  收藏  举报