zoukankan      html  css  js  c++  java
  • 策略模式小试

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

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

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

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

  • 相关阅读:
    vault验证导出领域对象导入新的shecma是否生效
    开启vault下如何使用expdp
    vault创建领域不让sys/system访问,但是可以让其他用户访问
    vault应用例子(禁止sys用户访问其他用户下的表)
    11g关闭vault
    11g配置vault
    11g单节点配置em
    vue中 js获取图片尺寸 设置不同样式
    vue 模块化 路由拆分配置
    vue 弹窗时 监听手机返回键关闭弹窗(页面不跳转)
  • 原文地址:https://www.cnblogs.com/zrtqsk/p/3732516.html
Copyright © 2011-2022 走看看