策略模式(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、一个系统需要动态地在几种算法中选择一种。

C#设计模式之21-策略模式的更多相关文章

  1. 【转】设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成 ...

  2. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  3. 《Head First 设计模式》[01] 策略模式

    <Head First 设计模式>(点击查看详情) 1.写在前面的话 之前在列书单的时候,看网友对于设计模式的推荐里说,设计模式的书类别都大同小异,于是自己就选择了Head First系列 ...

  4. javascript设计模式--策略模式

    javascript策略模式总结 1.什么是策略模式? 策略模式的定义是:定义一系列的算法,把他们独立封装起来,并且可以相互替换. 例如我们需要写一段代码来计算员工的奖金.当绩效为a时,奖金为工资的5 ...

  5. [head first 设计模式] 第一章 策略模式

    [head first 设计模式] 第一章 策略模式 让我们先从一个简单的鸭子模拟器开始讲起. 假设有个简单的鸭子模拟器,游戏中会出现各种鸭子,此系统的原始设计如下,设计了一个鸭子超类,并让各种鸭子继 ...

  6. Python设计模式: 最佳的"策略"模式实践代码

    Python设计模式: 最佳的"策略"模式实践代码 今天抽空看了下流畅的python,发现里面介绍了不少python自带的库的使用实例,用起来非常的优雅. 平时用Python来写爬 ...

  7. [设计模式] 21 策略模式 Strategy

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.该模式使得算法可独立于使用它的客户而变化. 策略模 ...

  8. [设计模式] javascript 之 策略模式

    策略模式说明 定义: 封装一系列的算法,使得他们之间可以相互替换,本模式使用算法独立于使用它的客户的变化. 说明:策略模式,是一种组织算法的模式,核心不在于算法,而在于组织一系列的算法,并且如何去使用 ...

  9. 设计模式学习之策略模式(Strategy,行为型模式)(13)

    转载地址:http://www.cnblogs.com/zhili/p/StragetyPattern.html 一.引言 本文要介绍的策略模式也就是对策略进行抽象,策略的意思就是方法,所以也就是对方 ...

  10. 设计模式:Strategy 策略模式 -- 行为型

    设计模式 策略模式Strategy(对象行为型) 这是几年前写的文字(转载做的笔记更准确些),发觉还是废话多了点. 其实,核心就是5.结构中的UML图 5.1 和 5.2(新增).现在看这张图就觉得一 ...

随机推荐

  1. redis未授权访问简单总结

    redis环境搭建 下载有漏洞的redis版本 wget http://download.redis.io/releases/redis-3.2.11.tar.gz 编译文件 make 进入src目录 ...

  2. GPO - General GPO Settings(2)

    Creating local folders and copying files  Mapping printers via GPO Deny logon locally.  Installation ...

  3. Java中lambda(λ)表达式的语法

    举一个排序的例子,我们传入代码来检查一个字符串是否比另一个字符串短.这里要计算: first.length() - second.length() first和second是什么?他们都是字符串.Ja ...

  4. 题解 CF613D 【Kingdom and its Cities】

    考虑树形\(DP\),设\(num_x\)记录的为当\(1\)为根时,以\(x\)为子树中重要城市的个数. 那么进行分类讨论: ① 当\(num_x≠0\)时,则需将其所有满足\(num_y≠0\)的 ...

  5. 题解 洛谷 P3521 【[POI2011]ROT-Tree Rotations】

    给定一棵二叉树,叶子节点有权值,可以进行若干次交换一个节点的左右儿子的操作,使前序遍历叶子的逆序对最少. 考虑一个节点下子树逆序对的产生: ① 只在左子树中产生. ② 只在右子树中产生. ③ 在左子树 ...

  6. WeChat 小程序开发

    第一步 去微信公众号平台注册> 一个账号https://mp.weixin.qq.com/ 填写完后 会获得一个APPID 2. 点击工具下载微信开发者工具安装即可, 1 2 3 微信开发者工具 ...

  7. Java代码片段

    type 为Java中的任意数据类型,包括基本类型和组合类型,arrayName为数组名,必须是一个合法的标识符,[ ] 指明该变量是一个数组类型变量.例如: 这两种形式没有区别,使用效果完全一样,读 ...

  8. 本地ES集群数据通过_reindex方式迁移到腾讯云服务器(亲测有效)

    本地ES集群数据通过_reindex方式迁移到腾讯云服务器(亲测有效) 随着业务量的增加,本地的ES集群服务器性能和磁盘空间有点不够使用,项目组考虑使用腾讯云服务器,以下是我测试的使用_reindex ...

  9. [leetcode/lintcode 题解] Amazon面试题:连接棒材的最低费用

    为了装修新房,你需要加工一些长度为正整数的棒材 sticks. 如果要将长度分别为 X 和 Y 的两根棒材连接在一起,你需要支付 X + Y 的费用. 由于施工需要,你必须将所有棒材连接成一根. 返回 ...

  10. 给隔壁的妹子讲『一个SQL语句是如何执行的?』

    前言 SQL作为Web开发是永远离开不的一个话题,天天写SQL,可是你知道一个SQL是如何执行的吗? select name from user where id = 1; 上面是一个简单的查询语句, ...