您的位置:首页 > 编程语言 > C#

c#设计模式之策略模式

2016-09-30 14:13 281 查看
策略模式的要点是封装一组算法,每个算法为独立的类,可以相互替代,因为它们有相似的行为。下面看一个具体的例子:



这是一个彩票网站,采用策略模式的真实案例。我们最终要计算不同彩种,不同方案,不同玩法的中奖率。3码:所有的3位数字,每位数字不能重复(022就不行),且按从小到大顺序排列。范围在012-789之间,4码:4位数字,推而广之,所谓几码,就是几位数字。因为时时彩是五位数字,所以有个十百千万

2期方案,就是把最近100期,按2期划分为一组,(100,99),(98,97)等等,总共有50组。同理,3期方案,就是把最近100期,每3期划分为一组。

那如何计算中奖率呢?以上图为模型,我们现在选择了新疆时时彩的最近100期,2期方案,考察个位和十位,计算3码、4码、5码、6码的中奖率。比如说3码中的 0,1,2的中奖率的计算方法,如下图所示:



这是从1期到10期的中奖号码,末尾为12的有3组,总共5组,那么中奖率为 3/5 。同理,如果100期,里面中奖的组有N个,总共有50组,所以中奖率为 N/50。

我们先定义一个抽象的玩法类:

public abstract class Play
{
/// <summary>
/// 中奖号码
/// </summary>
public List<string> PrizeNums { set; get; }

/// <summary>
/// 几期方案
/// </summary>
public int PeriodScheme{ set; get; }

/// <summary>
/// 选择的位数,比如选中个位和十位
/// </summary>
public string ChoosePositions { set; get; }

public Play(List<string> prizeNums,int period,string choosePositions)
{
this.PrizeNums = prizeNums;
this.PeriodScheme = period;
this.ChoosePositions = choosePositions;
}
public abstract Dictionary<string,double> ComputePrizeRate();
}


接下来是具体的实现类:

public class ThreeCodePlay : Play
{
public ThreeCodePlay(List<string> prizeNums, int period, string choosePositions)
: base(prizeNums, period, choosePositions)
{

}

public override Dictionary<string, double> ComputePrizeRate()
{
var rates = new Dictionary<string, double>();
//获取三码的所有数 (0,1,2)-(7,8,9)
//计算中奖率
return rates;
}
}


还有4码,五码,一直到九码,都需要实现。这里我就不赘述了。有兴趣的读者可自行实现。

接下来,我们需要一个决策类,这个类直接负责和客户端打交道。

public class PlayContext
{
private Play play;

public PlayContext(Play play)
{
this.play = play;
}
public Dictionary<string, double> GetPrizeRate()
{
return play.ComputePrizeRate();
}
}


客户端调用:

public class Client
{
public Dictionary<string, double> GetPrizeRate()
{
Play play = new ThreeCodePlay(new List<string>() { "01005" }, 3, "00011");
PlayContext context = new PlayContext(play);
return context.GetPrizeRate();
}
}


有读者读到这儿,觉得这个 Playcontext类是不是多余的呢?我客户端既然知道具体的玩法类,我可以直接调用玩法类计算中奖率,何必还要通过你PlayContext呢?再说了,你PlayContext类什么都没做啊。其实策略模式当中的算法就和我们公司的所有普通员工一样,直接上级领导类似PlayContext。其实PlayContext对play对象做了一个封装,封装使客户端和play类算法调用解耦,试想下,如果客户端直接调用play对象的计算方法,那么,如果play对象的算法名改变,那么我们是不是得改客户端的代码了。一个客户端好办,如果是很多个客户端,那么就是灾难。另外PlayContext类还可以添加其它方法,比如,客户端想要知道,3码的数一共是多少个,等等。

有读者可能觉得,你这个策略模式,明明需要客户端知道有哪些玩法,不等于还是把具体的玩法类暴露出来了。是的,为了进一步隔离客户端和玩法类,把构造玩法对象,放到PlayContext中,PlayContext根据条件,自行构造玩法对象。这不就成了简单工厂模式了吗?问题来了,简单工厂模式和策略模式到底有什么不同呢?

1、关注点不同:工厂模式封装的是复杂对象的创建,而策略模式封装的是一个对象的多种行为。PlayContex如果作为工厂,肯定返回一个play对象,如果作为策略,肯定执行一个Play对象的行为。

2、策略模式可以使客户端避免直接接触算法的一些细节,工厂模式可以使客户端不必关心对象的构造过程。

再举个额外的例子:

比如,我们下班回家有多种途径,1、坐公交 2、骑自行车 3、网约车 4、出租车 5、摩的 6、开车 7、走路 8、跑步 9、骑马 10、地铁 ,如果我们把回家看作一个对象的话,这个对象的行为方式实在多变。倒不是说,回家这个对象构造有多么复杂,而是我们能不能根据交通情况,自由地选择回家模式。

比如,在天空中可以飞的东西:1、飞机 2、鸟 3、风筝 4、气球 5、子弹 6、弓箭 7、孔明灯 8、 云朵 9、 雪花 10、ufo,如果我们把这些东西制造出来,是不是可以飞呢?倒不是说飞有多么难,关键是制造这些东西比较难,而且工艺都不同。

再回到我们玩彩票上来,倒不是玩彩票有多难,而是玩彩票的玩法实在太多,不同的玩法,意味着,中奖率的计算方法是不同的。所以这里着重是行为方式,用策略模式是恰当的选择。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: