一、引言
在讲策略模式之前,我们来看零售行业软件的一个针对客户类型打折的功能。
vip客户打八折,svip客户打七折。
代码实现:
if (customer == "vip") { amount = amount * 0.8; } else if (customer == "svip") { amount = amount * 0.7; }
看代码,挺简单的,但是如果今天vip打八折,明天要打7折,那还得改变原有的代码,这样就违背了开闭原则。这里变化的是折扣的计算方式(策略),策略模式就可以解决这类问题。
二、概念
策略模式是一种对象行为型模式。策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。
三、实现
策略模式包含三种角色:Context: 上下文类、Strategy: 抽象策略类、ConcreteStrategy: 具体策略类
抽象策略类:
public abstract class AbstractDiscountStrategy { public abstract decimal Discount(decimal amount); }
具体策略类:
public class VipDiscountStrategy:AbstractDiscountStrategy { public override decimal Discount(decimal amount) { return amount * 0.8M; } }
public class SVipDiscountStrategy:AbstractDiscountStrategy { public override decimal Discount(decimal amount) { return amount * 0.7M; } }
环境类:
public class StrategyContext { private AbstractDiscountStrategy discountStrategy; public StrategyContext(AbstractDiscountStrategy concreteDiscountStrategy) { this.discountStrategy = concreteDiscountStrategy; } public decimal ExecuteStrategy(decimal amount) { return this.discountStrategy.Discount(amount); } }
调用:
if (customer == "vip") { context = new StrategyContext(new VipDiscountStrategy()); amount = context.ExecuteStrategy(amount); } else if (customer == "svip") { context = new StrategyContext(new SVipDiscountStrategy()); amount = context.ExecuteStrategy(amount); }
可以看到,应用策略模式后,如果要修改vip客户的折扣计算方式,只需要修改对应的策略即可,不需要修改客户端的调用代码,也不会影响到svip的折扣计算方式,符合开闭原则。
再来一个ssvip客户,只需要增加一个对应的策略实现类,并且修改客户端的调用方法即可。
vip和svip的策略可以互换。
四、总结
从上面的例子可以看出来,策略模式的优点是提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
缺点也很明显,客户端必须清楚知道每一个策略的用途,并且自行决定使用哪一个策略,增加了客户端的负担,这个问题可以使用配置的方式来解决。每一个策略都需要一个类,会使策略类增多。