小看--策略模式
(一)什么是策略模式
定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。(这个在目前看来是句废话),接下来,通过了解策略模式的应用场景,大家就会明白策略模式了。
(二)策略模式的演变
场景,我们在做菜品促销的时候,通常都有9折,8折,7折,或者联合打折。
Console.WriteLine("........学习策略模式........."); double goodsPrice = 100.00; double discountPrice = 0.0; ; while (true){ Console.WriteLine("请输入商品折扣"); int discount =Convert.ToInt32(Console.ReadLine()); //假设有9折,8折,7折 switch (discount){ case 7: //打七折的时候,要多加十块 discountPrice = goodsPrice * 0.7 + 10; break; case 8: //打八折的时候,要多加十块 discountPrice = goodsPrice * 0.8 + 8; break; case 9: //打七折的时候,要多加十块 discountPrice = goodsPrice * 0.9 + 5; break; } Console.WriteLine($"打折后总价为:{discountPrice}");
可能一开始,我们大部分同学都会像我上面这么干,用一个SwitchCase就搞定了不同折扣之间的关系,但是我们觉得我们这样做好不好呢,如果我们现在要增加一个打六折的东西,那又来改上端代码,这种做法呢,是属于面向过程的,完全没有体会到面向对象的思想,那么我们就应该多想一点,想深入一点,那该怎么做呢,可能有的同学就会想了,进行一个抽象(封装类,屏蔽细节)。
所以接下来就有了我们这个版本的:
while (true) { Console.WriteLine("请输入商品折扣"); int discount = Convert.ToInt32(Console.ReadLine()); IStrategy gy = null; //假设有9折,8折,7折 switch (discount) { case 7: //打七折的时候,要多加十块 //discountPrice = goodsPrice * 0.7 + 10; gy=new Seven(); break; case 8: //打八折的时候,要多加十块 //discountPrice = goodsPrice * 0.8 + 8; gy = new Eight(); break; case 9: //打七折的时候,要多加十块 //discountPrice = goodsPrice * 0.9 + 5; gy = new Night(); break; } Console.WriteLine($"打折后总价为:{gy.GetDiscountPrice(100)}"); //这个100是商品的原价 }
这个版本的改进:主要是我们把之前的打折的方法,都分别封装到类里面,然后实现了这些类都实现了IStratgy接口(如下图所示);,所以我们的代码改成了上面这个结构。
到了这里,我们都要明白我们已经做到了开放抽象给上端了,上端是不依赖具体的细节了。
我们继续,我们发现现在上端需要做的事情,1、接收用户的的输入选择相应的算法,2、执行相应的算法。
在这里,我们这个例子中,执行算法,可能是比较简单一点,这里需要大家有点想像一下,我们实际中的,算法执行,可能非常复杂,可能需要进行写日志呀,根据不同的会员等级,对应的打折价格都是不一样的,很复杂。
所以这里对于上端执行算法呢,我们要引入一个上下文(Context)。大家也可以延伸想一想,HttpContext:就是用来保存http的一些状态信息,Cookie,Session等等。我们这个上下文对象就是用来保存这次算法执行的一些初始化信息,中间变量,结果值等等(因为我们刚刚已经说,这个算法的执行是非常复杂的,需要做很多的准备)。
public class DiscountContext { private readonly double _oldPrice;private readonly IStrategy _strategy; public DiscountContext(double oldPrice,IStrategy strategy){this._oldPrice = oldPrice; this._strategy = strategy; } public double Excute(){ //很复杂的操作,不同操作系统,对应不同策略等等。 Console.WriteLine("写日志"); Console.WriteLine("做缓存"); return this._strategy.GetDiscountPrice(this._oldPrice); }
引入了这个类之后呢,我们上端也要进行修改一下;
Console.WriteLine("请输入商品折扣"); int discount = Convert.ToInt32(Console.ReadLine()); IStrategy gy = null; //假设有9折,8折,7折 switch (discount) { case 7: //打七折的时候,要多加十块 //discountPrice = goodsPrice * 0.7 + 10; gy=new Seven(); break; case 8: //打八折的时候,要多加十块 //discountPrice = goodsPrice * 0.8 + 8; gy = new Eight(); break; case 9: //打七折的时候,要多加十块 //discountPrice = goodsPrice * 0.9 + 5; gy = new Night(); break; } var disContext=new DiscountContext(100,gy); Console.WriteLine($"打折后总价为:{disContext.Excute()}");
到此,我们的策略模式就结束了。下面来对上面进行一个总结:所谓的策略模式,首先要有很多策略(算法)先,才需要对所有策略,进行一个公共的抽取,让所有策略都继承自抽象;然后因为每个策略执行的复杂性以及诸多因素,我们需要把策略的执行过程,封装为一个上下文。策略模式的三要素:1、策略(有很多策略),2、策略的接口,3、上下文;
(三)策略模式的优缺点
优缺点,大家从上面应该是显而易见的了,优点:算法之间,可以自由转换。
缺点:没一个算法类的复用性不高,增加了很多类。
(四)策略模式和工厂模式结合
由于时间关系,大家可以想想该怎么做。