策略模式小试

来源:互联网 发布:驱动精灵for mac 编辑:程序博客网 时间:2024/06/03 21:27

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

转载请注明出处:http://www.cnblogs.com/zrtqsk/p/3732516.html,谢谢!

一、介绍

  看一下《研磨设计模式》里的介绍——定义一系列的算法,把它们一个个封装起来,并且使他们可相互替换。本模式使得算法可独立于使用它的客户而变化。

  策略模式的本质是——分离算法、选择实现。

  什么意思呢?我们知道什么是算法,简单而言就是计算某种事物的方法。我们都知道排序,最常见的排序包括冒泡排序、快速排序、堆排序、直接插入排序等等很多。这里的排序方法就是算法。每一种排序都有各自不同的特点,适用于不同的情况。如果将这些算法封装起来,以便随时选择切换,这就是策略模式的本质了。

  那么怎么实现策略模式呢?说白了就是从众多算法实现中抽象出一个接口,然后众算法都实现这个接口,然后调用者呢,就持有这个接口,于是就可以使用这个算法了。

  理解策略模式,可以从“策略”二字着手。什么是策略?就是解决问题的方法、对策!策略模式,就是切换方法的模式!就这么简单。怎么切换方法呢?将方法放进接口,让不同的策略去实现这个接口,然后就可以自由的切换了。

  任何的算法实现,我们都可以用策略模式将其包装一下,实现算法的自由切换。

 

二、我的实现

  假设现在有一个游戏。我们设定正常情况下,玩家获得的游戏分数是固定的。玩家红名时获得分数减半;节假日,所有玩家获得分数翻倍;游戏会员获得分数加成,加成效果与会员等级有关;为了操作方便,还可以指定分数加成值。现在我们把这个分数加成算法包装一下。

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     @Override13     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     @Override11     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         // 分数上下文,持有所有的加成状态,并设置基础分为100014         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     }
复制代码

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

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

0 0
原创粉丝点击