定义
在现实生活中,策略模式的例子也非常常见,例如,中国的所得税,分为企业所得税、外商投资企业或外商企业所得税和个人所得税,针对这3种所得税,针对每种,所计算的方式不同,个人所得税有个人所得税的计算方式,而企业所得税有其对应的计算方式。如果不采用策略模式来实现这样一个需求,可能我们会定义一个所得税类,该类有一个属性来标记所得税的类型,并且有一个计算税收的方法,在该方法体内需要对税收类型进行判断,通过条件语句来针对不同的税收类型来计算其所得税。这样的确可以实现这个需求,但是这样的设计不利于扩展,如果系统后期需要增加一种所得税时,就需要去修改计算方法,新增判断语句,这样违背了“开闭”原则。这个需求可以用策略者模式来实现。
结构
策略者模式是对算法的包装,是把使用算法的责任和算法本身分开来,委派给不同的对象负责。策略模式通常把一系列的算法包装到一系列的策略类里面。
涉及到的角色有:
- 环境角色(Context):持有一个Stragety类的引用
- 抽象策略角色(Stragety):抽象角色,通常由一个接口或者抽象类来实现。给出所有具体策略类所需实现的接口
- 具体策略角色(ConcreteStragety):包装了相关算法或行为
实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _36StragetyPatternDemo
{
//所得税计算策略
public interface ITaxStragety
{
double CalculateTax(double income);
}
//个人所的税
public class PersonTaxStragety : ITaxStragety
{
public double CalculateTax(double income)
{
return income * 0.12;
}
}
//企业所得税
public class EnterpriseTaxStragety : ITaxStragety
{
public double CalculateTax(double income)
{
return (income - 3500) > 0 ? (income - 3500) * 0.045 : 0.0;
}
}
public class InterestOperation
{
private ITaxStragety m_stragety;
public InterestOperation(ITaxStragety stragety)
{
this.m_stragety = stragety;
}
public double GetTax(double income)
{
return m_stragety.CalculateTax(income);
}
}
class Program
{
static void Main(string[] args)
{
//个人所得税方式
InterestOperation operation = new InterestOperation(new PersonTaxStragety());
Console.WriteLine("个人所得税为:{0}",operation.GetTax(5000.00));
//企业所得税方式
operation = new InterestOperation(new EnterpriseTaxStragety());
Console.WriteLine("企业支付的税为:{0}",operation.GetTax(50000.00));
}
}
}
适用场景
- 一个系统需要动态地在几种算法中选择一种的情况下。那么这些算法可以包装到一个个具体的算法类里面,并为这些具体的算法类提供一个统一的接口
- 如果一个对象有很多行为,如果不使用适合的模式,这些行为就只要使用多重的if-else语句来实现,此时,可以使用策略者模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。
优缺点
优点
- 策略类之间可以自由切换。由于策略类都实现同一个接口,所以使它们之间可以自由切换
- 易于扩展。增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码。
- 避免使用多重条件选择语句,充分体现面向对象设计思想
缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这点可以考虑使用IOC容器和依赖注入的方式来解决。
- 策略模式会产生很多的策略类
总结
策略模式主要是对方法的封装,把一系列方法封装到一系列的策略类中,从而使不同的策略类可以自由切换和避免在系统使用多重条件选择语句来选择针对不同情况来选择不同的方法。