策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得可以根据具体场景来使用不同算法。策略模式使得算法可以在不影响到客户端的情况下发生变化。
在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。如查找、排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难。如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。
结构:
模式的组成:
环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。
抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
使用场景:
例如现在商店打折促销,促销策略分为第一就是产品数量不足100个的情况下按照八折来获取总价,如果超过100个送十个然后在获取总价,打折策略和买满就送策略分别为两个策略,根据具体场景选择不同销售策略此处的场景就是购买产品小于100就打折大于100就送这两个策略,这样的话我们首先要添加个销售接口类并且有一个方法来计算总价代码如下:
/// <summary>
/// 销售策略接口
/// </summary>
public interface ISaleStrategy
{
/// <summary>
/// 返利接口--根据购买的产品数量进行返利
/// </summary>
/// <param name="productCount">产品数量</param>
/// <param name="unitPrice">单价</param>
/// <returns></returns>
double GetTotalPrice(int productCount, double unitPrice);
}
下面我们在写打折和满减策略类来继承接口:
/// <summary>
/// 打折返利--八折
/// </summary>
public class DiscountStrategy:ISaleStrategy
{
/// <summary>
/// 打八折优惠
/// </summary>
/// <param name="productCount"></param>
/// <param name="unitPrice"></param>
/// <returns></returns>
public double GetTotalPrice(int productCount, double unitPrice)
{
Console.WriteLine("打八折");
return productCount * unitPrice*0.8;
}
}
/// <summary>
/// 超过100就送10个---买满就送策略
/// </summary>
public class ReturnCountGreaterThanOneHundredSaleStrategy : ISaleStrategy
{
/// <summary>
/// 购买产品超过100就送10个
/// </summary>
/// <param name="productCount"></param>
/// <param name="unitPrice"></param>
/// <returns></returns>
public double GetTotalPrice(int productCount, double unitPrice)
{
Console.WriteLine("满100就送10");
return (productCount - 10)*unitPrice;
}
}
接下来我们在写一个策略上下文用来获取销售策略对象代码如下:
public class StrategyContext
{
/// <summary>
/// 获取销售策略对象
/// </summary>
/// <param name="productCount">产品数量</param>
/// <returns>如果购买产品小于100的话就返回打折销售对象如果大于100就返回买满就送策略</returns>
public ISaleStrategy GetSaleStrategy(int productCount)
{
ISaleStrategy salteStrategy = null;
if (productCount < 100)
{
salteStrategy = new DiscountStrategy();
}
else
{
salteStrategy = new ReturnCountGreaterThanOneHundredSaleStrategy();
}
return salteStrategy;
}
static void Main(string[] arge)
{
//购买产品数量--默认10个
int productCount = 10;
//默认每个产品价格是100
double unitPrice = 100;
StrategyContext strategyContext = new StrategyContext();
var saleStategy = strategyContext.GetSaleStrategy(productCount);
var totalPrice = saleStategy.GetTotalPrice(productCount, unitPrice);
Console.WriteLine($"产品数量为{productCount}个的时候总价为{totalPrice}");
productCount = 100;
totalPrice = 0;
var saleStategy1 = strategyContext.GetSaleStrategy(productCount);
totalPrice = saleStategy1.GetTotalPrice(productCount, unitPrice);
Console.WriteLine($"产品数量为{productCount}个的时候总价为{totalPrice}");
Console.ReadLine();
}
}
运行结果如下:
销售策略需要使用的情况:策略本质是一种行为不同实现方式,需要根据具体环境来选择不同的策略,减少了if else条件语句中的代码量,例如上面根据产品数量来获取不同的产品总价用if else语句完全可以做到,根本不需要用到策略类,上面只是为了演示策略模式,但是如果每种策略很复杂如果再用if else的话代码会很多不容易维护,如果在加一种策略的话会很麻烦,所以此时可以使用策略模式来设计代码;这样便于维护易于扩展。