在讲策略模式之前,我们先看一个日常生活中的小例子:
现实生活中我们到商场买东西的时候,卖场往往根据不同的客户制定不同的报价策略,比如针对新客户不打折扣,针对老客户打9折,针对VIP客户打8折...
现在我们要做一个报价管理的模块,简要点就是要针对不同的客户,提供不同的折扣报价。
如果是有你来做,你会怎么做?如果没有策略模式,可能会用大量的if-else if 或者switch,再或者是将每个计算方法封装到相应的方法中去调用。
但是这样的代码会有很多问题:
1.当我们新增一个客户类型的时候,首先要添加一个该种客户类型的报价算法方法,然后再quote方法中再加一个else if的分支,是不是感觉很是麻烦呢?而且这也违反了设计原则之一的开闭原则(open-closed-principle).
开闭原则:
对于扩展是开放的(Open forextension)。这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。也就是说,我们可以改变模块的功能。
对于修改是关闭的(Closed for modification)。对模块行为进行扩展时,不必改动模块的源代码或者二进制代码。
2.我们经常会面临这样的情况,不同的时期使用不同的报价规则,比如在各个节假日举行的各种促销活动时、商场店庆时往往都有普遍的折扣,但是促销时间一旦过去,报价就要回到正常价格上来。按照上面的代码我们就得修改if else里面的代码很是麻烦
定义:
策略模式定义了一些列的算法,并将每一个算法封装起来,使每个算法可以互相替代,使算法本身的和使用算法的客户端分割开来,相互独立。
UML图

UML序列图

实现
针对我们一开始讲的报价管理的例子:我们可以应用策略模式对其进行改造,不同类型的客户有不同的折扣,我们可以将不同类型的客户的报价规则都封装为一个独立的算法,然后抽象出这些报价算法的公共接口
报价策略接口:
/// <summary>
/// 报价策略接口
/// </summary>
interface IQuoteStrategy
{
float GetPrice(float originalPrice);
}
新客户报价策略实现:
/// <summary>
/// 新用户报价策略
/// </summary>
class NewCustomQuoteStrategy : IQuoteStrategy
{
public float GetPrice(float originalPrice)
{
Console.WriteLine("抱歉,新用户没有折扣");
return originalPrice;
}
}
老客户报价策略实现:
/// <summary>
/// 老客户报价策略
/// </summary>
class OldCustomQuoteStrategy : IQuoteStrategy
{
public float GetPrice(float originalPrice)
{
Console.WriteLine("老用户9折");
return originalPrice * 0.9f;
}
}
VIP客户报价实现:
/// <summary>
/// VIP客户报价策略
/// </summary>
class VIPCustomStrategy : IQuoteStrategy
{
public float GetPrice(float originalPrice)
{
Console.WriteLine("VIP客户8折");
return originalPrice * 0.8f;
}
}
报价上下文
/// <summary>
/// 报价上下文
/// </summary>
class QuoteContext
{
private IQuoteStrategy strategy;
/// <summary>
/// 注入报价策略
/// </summary>
/// <param name="strategy"></param>
public QuoteContext(IQuoteStrategy strategy)
{
this.strategy = strategy;
}
/// <summary>
/// 回调具体报价策略方法
/// </summary>
/// <param name="originalPrice"></param>
/// <returns></returns>
public float GetPrice(float originalPrice)
{
return strategy.GetPrice(originalPrice);
}
}
外部客户端
/// <summary>
/// 外部客户端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.创建老用户的报价策略
IQuoteStrategy oldQuoteStrategy = new OldCustomQuoteStrategy();
//2.创建报价上下文对象,并设置具体的报价策略
QuoteContext quoteContext = new QuoteContext(oldQuoteStrategy);
//3.调用报价上下文的方法
float price = quoteContext.GetPrice(100);
Console.WriteLine(price);
}
}
这个时候,商场营销部新推出了一个客户类型--MVP用户(Most Valuable Person),可以享受折扣7折优惠,那该怎么办呢?
这个很容易,只要新增一个报价策略的实现,然后外部客户端调用的时候,创建这个新增的报价策略实现,并设置到策略上下文就可以了,对原来已经实现的代码没有任何的改动。
/// <summary>
/// MVP客户报价策略
/// </summary>
class MVPCustomStrategy : IQuoteStrategy
{
public float GetPrice(float orginalPrice)
{
Console.WriteLine("MVP客户7折");
return orginalPrice * 0.7f;
}
}
/// <summary>
/// 外部客户端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.创建MVP用户的报价策略
IQuoteStrategy oldQuoteStrategy = new MVPCustomStrategy();
//2.创建报价上下文对象,并设置具体的报价策略
QuoteContext quoteContext = new QuoteContext(oldQuoteStrategy);
//3.调用报价上下文的方法
float price = quoteContext.GetPrice(100);
Console.WriteLine(price);
}
}
深入理解策略模式
策略模式的作用
就是把具体的算法实现从业务逻辑中剥离出来,成为一系列独立算法类,使得它们可以相互替换。
策略模式的着重点
不是如何实现算法,而是如果组织和调用这些算法,从而让我们的程序结构更加的灵活、可扩展。
策略模式就是把各个平等的具体实现进行抽象、封装成为独立的算法类,然后通过上下文和具体的算法类来进行交互。各个策略算法都是平等的,地位是一样的,正是由于各个算法的平等性,所以它们才是可以相互替换的。虽然我们可以动态切换各个策略,但是同一时刻只能使用一个策略。
网友评论