还是那几句话:
学无止境,精益求精
十年河东,十年河西,莫欺少年穷
学历代表你的过去,能力代表你的现在,学习代表你的将来
废话不多说,直接进入正题:
首先按照大话设计模式的解释,在这里也总结下策略模式的概念:它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户!
具体的实现代码为:
namespace SJMS { /// <summary> /// 抽象算法类 /// </summary> public abstract class Strategy { /// <summary> /// 抽象算法 /// </summary> public abstract void AlgorithmInterface(); } /// <summary> /// 具体算法A /// </summary> public class ConcreteStrategyA : Strategy { /// <summary> /// 算法A的具体实现方法 /// </summary> public override void AlgorithmInterface() { Console.WriteLine("算法A的具体方法"); } } /// <summary> /// 具体算法B /// </summary> public class ConcreteStrategyB : Strategy { /// <summary> /// 算法B的具体实现方法 /// </summary> public override void AlgorithmInterface() { Console.WriteLine("算法B的具体方法"); } } /// <summary> /// 抽象算法C /// </summary> public class ConcreteStrategyC : Strategy { /// <summary> /// 算法C的具体实现方法 /// </summary> public override void AlgorithmInterface() { Console.WriteLine("算法C的具体方法"); } } public class Context { private Strategy _strategy; /// <summary> /// 用于维护抽象算法类对象 /// </summary> public Context(Strategy strategy) { this._strategy = strategy; } /// <summary> /// 根据维护的不同对象,调用对应的算法 /// </summary> public void ContextInterface() { _strategy.AlgorithmInterface(); } } }
输出端调用代码为:
static void Main(string[] args) { Context context; //由Context维护得到算法A的对象,并由算法A的对象执行算法A context = new Context(new ConcreteStrategyA()); context.ContextInterface(); //由Context维护得到算法B的对象,并由算法A的对象执行算法B context = new Context(new ConcreteStrategyB()); context.ContextInterface(); //由Context维护得到算法C的对象,并由算法A的对象执行算法C context = new Context(new ConcreteStrategyC()); context.ContextInterface(); }
策略模式的类图为:
看到上述代码和类图,现在的你是不是一头雾水?
既然一头雾水,那么我们就静下心来分析下代码的实现
1、Strategy.cs 主要的功能是:抽象算法类,被各个具体的算法类继承,抽象方法被重写成各个具体的算法!
2、ConcreteStrategyA.cs、ConcreteStrategyB.cs、ConcreteStrategyC.cs、ConcreteStrategyD.cs.......等用于实现具体的算法
针对第二点,在这里举个例子:某一个商场促销,搞了很多活动,例如:年初一所有商品打一折,年初二所有商品打二折,....年初九所有商品打九折!元宵节针对所有商品推出消费满500减200的活动,清明节针对所有商品推出消费满800立减300的活动!六一儿童节推出消费N元送N积分的活动!国庆节,中秋节推出消费N元送N积分并优惠N/3元的活动等等等
在这里,一些列打折的活动可以看作算法A。消费满N元送M元的活动可看作算法B。消费N元送N积分的活动可以看作算法C。消费N元送N积分并且优惠N/3 元的活动可看作算法D。等等吧!总之商场可以推出N中不同算法的活动!
3、Context.cs 主要的功能是根据客户端不同的调用:context = new Context(new ConcreteStrategyA()); context.ContextInterface(); 来创建对应的对象并根据创建的对象,确定执行哪个算法。
针对第三点中加粗的文字:来创建对应的对象并根据创建的对象,确定执行哪个算法。上一节中我们讨论了简单工厂模式,我们知道简单工厂模式中的工厂就是负责生产不同的对象!因此,在这方面(生产对象),策略模式和简单工厂模式非常相似!
那么,在实际的代码中,我们怎么来构造策略模式呢?
在此,按照上述商场促销活动的例子,我们先用简单工厂模式实现,如下:
#region 简单工厂模式实现 /// <summary> /// 简单工厂模式实现 /// </summary> public class CashFactory { public static CaseSuper GetResult(string type) { CaseSuper Model = null; switch (type) { case "原价出售": Model = new CaseNormal(); break; case "打八折": Model = new CaseRebate("0.8"); break; case "满五百返两百": Model = new CaseRerurn("500", "200"); break; } return Model; } } /// <summary> /// 抽象类 /// </summary> public abstract class CaseSuper { /// <summary> /// 原价 /// </summary> /// <param name="money">返回原价:不打折</param> /// <returns></returns> public abstract double acceptCash(double Money); } /// <summary> /// 正常收费 /// </summary> public class CaseNormal : CaseSuper { public override double acceptCash(double Money) { return Money; } } /// <summary> /// 打折收费 /// </summary> public class CaseRebate : CaseSuper { private double rebate = 1d; public CaseRebate(string Rebate) { rebate = Convert.ToDouble(Rebate); } public override double acceptCash(double Money) { return Money * rebate; } } public class CaseRerurn : CaseSuper { private double moneyContion = 0d; private double returnMoney =0d; public CaseRerurn(string MoneyContion,string ReturnMoney) { returnMoney = Convert.ToDouble(ReturnMoney); moneyContion = Convert.ToDouble(MoneyContion); } public override double acceptCash(double Money) { if (Money >= moneyContion) { return Money - returnMoney; } else { return Money; } } } #endregion
输出端调用如下:
static void Main(string[] args) { CaseSuper M = CashFactory.GetResult("原价出售"); Console.WriteLine("原价返回:" + M.acceptCash(900)); // CaseSuper M2 = CashFactory.GetResult("打八折"); Console.WriteLine("打八折:" + M2.acceptCash(900)); // CaseSuper M3 = CashFactory.GetResult("满五百返两百"); Console.WriteLine("满五百返两百:" + M3.acceptCash(900)); Console.ReadKey(); }
上述便是我们利用简单工程模式实现的代码,不过,在这里,我们会发现上述代码的我们对策略模式的讨论几乎一样,至少少了个 Context.cs 类。
在此,我们按照上述的思路构建 Context.cs 类,如下:
#region 策略模式 public class CashContexts { private CaseSuper _caseSuper; /// <summary> /// 用于维护抽象算法类对象 /// </summary> public CashContexts(CaseSuper caseSuper) { this._caseSuper = caseSuper; } /// <summary> /// 根据维护的不同对象,调用对应的算法 /// </summary> public double acceptCash(double Money) { return _caseSuper.acceptCash(Money); } } #endregion
输出端调用代码为:
static void Main(string[] args) { //策略模式 string types = Console.ReadLine(); CaseSuper M = null; switch (types) { case "打八折": M = new CaseRebate("0.8"); break; case "打五折": M = new CaseRebate("0.5"); break; case "满五百返两百": M = new CaseRerurn("500", "200"); break; } CashContexts context = new CashContexts(M); double Money = context.acceptCash(900); Console.WriteLine(types + ":" + Money); Console.ReadKey(); }
上述代码,输出端的代码 Switch 是没必要存在的,因为多个输出端调用会造成代码的重复,结合工厂模式,我们把 Context.cs 类衍生出如下类:
即:简单工厂模式与策略模式相结合
public class CashContext { private CaseSuper cs; public CashContext(string type) { switch (type) { case "原价出售": cs = new CaseNormal(); break; case "打八折": cs = new CaseRebate("0.8"); break; case "满五百返两百": cs = new CaseRerurn("500", "200"); break; } } // public double acceptCash(double Money) { return cs.acceptCash(Money); } }
OK,上述便是策略模式,我在看来策略模式和简单工厂模式非常相似。一个是创建对象的工厂,一个是具体执行哪个算法的策略。
简单工厂模式与策略模式的区别在于:
相似点
在模式结构上,两者很相似;
差异
- 用途不一样
工厂是创建型模式,它的作用就是创建对象;
策略是行为型模式,它的作用是让一个对象在许多行为中选择一种行为;
-
关注点不一样
一个关注对象创建
一个关注行为的封装 -
解决不同的问题
工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。
策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。 -
工厂相当于黑盒子,策略相当于白盒子;
举例说明
-
工厂模式
有一天你决定去吃培根披萨,首先得选择店铺,A店和B店都有培根披萨;
你点了A店的培根披萨,过了二十分钟,你的披萨就来了就可以吃到了。但这个披萨是怎么做的,到底面粉放了多少,培根放了多少,佐料放了多少,有多少道工序,你是不需要管的,你需要的是一个美味培根披萨。 -
策略模式
在披萨店,你要一个培根披萨,老板说有标准的pizza,也可以自己去做。原料有培根、面粉、佐料。工序有1、2、3工序,你自己去做吧。然后你就需要自己去做,到底放多少培根,放多少面粉,放多少佐料,这都你自己来决定,工序1、2、3,你是怎么实现的,都你自己决定。最后你得到了披萨。 - 当然,大家可自行查阅资料、
@陈卧龙的博客