策略模式(Stragety Pattern)

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/427 访问。

策略模式属于行为型模式,它定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。

使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类中提供。

角色:

1、抽象策略(Strategy)

这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口;

2、具体策略(Concrete Strategy)

实现抽象策略的具体策略类,包装了相关的算法或行为;

3、环境类(Context)

持有一个Strategy类的引用并可以根据逻辑选择实例相应的策略。

示例:

命名空间StragetyPattern中包含策略基类Tax以及它的8个实现类,Context环境类持有策略基类。本示例通过一个优雅的方式来计算个人所得税。

C#开发笔记之04-如何用C#优雅的计算个人所得税?

namespace StragetyPattern
public abstract class Tax {

    protected decimal TaxRate = 0;

    protected decimal QuickDeduction = 0;

    public virtual decimal Calculate(decimal income) {
return income * TaxRate - QuickDeduction;
} }

策略基类Tax,表示个人所得税,TaxRate为税率,QuickDeduction为速算扣除数,Calculate计算相应收入的个人所得税。

public class Level0 : Tax {

    public Level0() {
TaxRate = 0.00m;
QuickDeduction = 0;
} }

0级个人所得税阶梯,表示个人所得税的初始状态。

public class Level1 : Tax {

    public Level1() {
TaxRate = 0.03m;
QuickDeduction = 0;
} }

1级个人所得税阶梯。

public class Level2 : Tax {

    public Level2() {
TaxRate = 0.10m;
QuickDeduction = 105;
} }

2级个人所得税阶梯。

public class Level3 : Tax {

    public Level3() {
TaxRate = 0.20m;
QuickDeduction = 555;
} }

3级个人所得税阶梯。

public class Level4 : Tax {

    public Level4() {
TaxRate = 0.25m;
QuickDeduction = 1005;
} }

4级个人所得税阶梯。

public class Level5 : Tax {

    public Level5() {
TaxRate = 0.30m;
QuickDeduction = 2755;
} }

5级个人所得税阶梯。

public class Level6 : Tax {

    public Level6() {
TaxRate = 0.35m;
QuickDeduction = 5505;
} }

6级个人所得税阶梯。

public class Level7 : Tax {

    public Level7() {
TaxRate = 0.45m;
QuickDeduction = 13505;
} }

7级个人所得税阶梯。

public class Context {

    private Tax _tax = null;

    private const decimal EXEMPTION_VALUE = 3500m;

    private List<decimal> _taxLevel = new List<decimal>{
0,
1500,
4500,
9000,
35000,
55000,
80000,
decimal.MaxValue
}; private List<Type> _levels = new List<Type>(); private void GetLevels() {
_levels = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(tp => tp.GetTypes()
.Where(t => t.BaseType == typeof(Tax)))
.ToList();
} public Context() {
GetLevels();
} public Context Calculate(decimal income) {
_tax = new Level0();
var result = income - EXEMPTION_VALUE;
for(int i = 1; i <= _taxLevel.Count - 1; i++) {
if(result > _taxLevel[i - 1] && result <= _taxLevel[i]) {
_tax = (Tax)Activator.CreateInstance(_levels[i]);
}
}
Console.WriteLine($"Income = {income}," + $"tax = {_tax.Calculate(result)}!");
return this;
} }

环境类Context,首先需要维持对Tax的引用,EXEMPTION_VALUE表示免征额(本例使用3500元),之后通过反射和一些技巧选择相应的Tax实现类来计算相应阶梯的个人所得税。

public class Program {

    private static Context _context = new Context();

    public static void Main(string[] args) {
_context.Calculate(2500.00m)
.Calculate(4900.00m)
.Calculate(5500.00m)
.Calculate(7000.00m)
.Calculate(10000.00m)
.Calculate(16000.00m)
.Calculate(43000.00m)
.Calculate(70000.00m)
.Calculate(100000.00m)
.Calculate(4500.00m)
.Calculate(1986.00m); Console.ReadKey();
} }

以上是调用方的代码,Calculate经过特殊处理以支持方法链。以下是这个案例的输出结果:

Income = 2500.00,tax = 0.0000!
Income = 4900.00,tax = 42.0000!
Income = 5500.00,tax = 95.0000!
Income = 7000.00,tax = 245.0000!
Income = 10000.00,tax = 745.0000!
Income = 16000.00,tax = 2120.0000!
Income = 43000.00,tax = 9095.0000!
Income = 70000.00,tax = 17770.0000!
Income = 100000.00,tax = 29920.0000!
Income = 4500.00,tax = 30.0000!
Income = 1986.00,tax = 0.0000!

优点:

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/427 访问。

1、策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码;

2、继承可以处理多种算法或行为,可以避免使用多重条件转移语句。

缺点:

1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类;

2、策略模式造成很多的策略类,造成“子类爆炸”。

使用场景:

1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为;

2、一个系统需要动态地在几种算法中选择一种。

最新文章

  1. C#冒泡排序算法
  2. nodevalue
  3. javascript变量、作用域和内存问题......
  4. poj3070 (斐波那契,矩阵快速幂)
  5. 远程实时调试手机上的Web页面
  6. webpack.config.js
  7. html5 canvas图片翻转
  8. The Swift Programming Language--语言指南--协议
  9. Shell中的算术运算(译)
  10. hash在URL上的用法及作用
  11. 关于跨DB增量(增、改)同步两张表的数据小技巧
  12. VSTO:使用C#开发Excel、Word【13】
  13. 【Qt】窗口居中显示
  14. Centos 使用find查找
  15. sqlserver 2008 还原数据库时,提示有用户正在使用,无法取得使用占有权
  16. m2e 插件
  17. 一个好用的ssh终端:MobaXterm
  18. 火狐浏览器(firefox)中js要注意的问题
  19. Sencha Touch快速入门(译)
  20. WPF中Grid实现网格,表格样式通用类(转)

热门文章

  1. 一起学Blazor WebAssembly 开发(3)
  2. Just test it!!软件测试测起来!!
  3. ajax提交表单,包括跳入的坑!
  4. Spring Security 实战干货:理解AuthenticationManager
  5. css中的名词
  6. 【新生学习】第一周:深度学习及pytorch基础
  7. sql数据管理语句
  8. 手写 promies
  9. Kali小技巧
  10. Python os.tmpfile() 方法