状态模式是对某个对象状态的抽象,而本文要介绍的策略模式也就是对策略进行抽象,策略的意思就是方法,所以也就是对方法的抽象,下面具体分享下我对策略模式的理解。

一、 策略者(Stragety)模式

在现实生活中,策略模式的例子也非常常见,例如,中国的所得税,分为企业所得税、外商投资企业或外商企业所得税和个人所得税,针对于这3种所得税,针对每种,所计算的方式不同,个人所得税有个人所得税的计算方式,而企业所得税有其对应计算方式。如果不采用策略模式来实现这样一个需求的话,可能我们会定义一个所得税类,该类有一个属性来标识所得税的类型,并且有一个计算税收的CalculateTax()方法,在该方法体内需要对税收类型进行判断,通过if-else语句来针对不同的税收类型来计算其所得税。这样的实现确实可以解决这个场景吗,但是这样的设计不利于扩展,如果系统后期需要增加一种所得税时,此时不得不回去修改CalculateTax方法来多添加一个判断语句,这样明白违背了“开放——封闭”原则。此时,我们可以考虑使用策略模式来解决这个问题,既然税收方法是这个场景中的变化部分,此时自然可以想到对税收方法进行抽象。

前面介绍了策略模式用来解决的问题,下面具体给出策略的定义。策略模式是针对一组算法,将每个算法封装到具有公共接口的独立的类中,从而使它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

二、 策略者模式的结构

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象负责。策略模式通常把一系列的算法包装到一系列的策略类里面。用一句话慨括策略模式就是——“将每个算法封装到不同的策略类中,使得它们可以互换”。

下面是策略模式的结构图:

该模式涉及到三个角色:

  • 环境角色(Context):持有一个Strategy类的引用
  • 抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类来实现。此角色给出所有具体策略类所需实现的接口。
  • 具体策略角色(ConcreteStrategy):包装了相关算法或行为。

三、 策略者模式的实现

下面就以所得税的例子来实现下策略模式,具体实现代码如下所示:

using System;namespace StrategyPattern
{// 所得税计算策略public interface ITaxStragety{double CalculateTax(double income);}// 个人所得税public class PersonalTaxStrategy : ITaxStragety{public double CalculateTax(double income){return income * 0.12;}}// 企业所得税public class EnterpriseTaxStrategy : ITaxStragety{public double CalculateTax(double income){return (income - 3500) > 0 ? (income - 3500) * 0.045 : 0.0;}}public class InterestOperation{private readonly ITaxStragety _mStrategy;public InterestOperation(ITaxStragety strategy){this._mStrategy = strategy;}public double GetTax(double income){return _mStrategy.CalculateTax(income);}}class App{static void Main(string[] args){// 个人所得税方式var operation = new InterestOperation(new PersonalTaxStrategy());Console.WriteLine("个人支付的税为:{0}", operation.GetTax(5000.00));// 企业所得税operation = new InterestOperation(new EnterpriseTaxStrategy());Console.WriteLine("企业支付的税为:{0}", operation.GetTax(50000.00));Console.Read();}}
}

四、 策略者模式在.NET中应用

在.NET Framework中也不乏策略模式的应用例子。例如,在.NET中,为集合类型ArrayList和List<T>提供的排序功能,其中实现就利用了策略模式,定义了IComparer接口来对比较算法进行封装,实现IComparer接口的类可以是顺序,或逆序地比较两个对象的大小,具体.NET中的实现可以使用反编译工具查看List<T>.Sort(IComparer<T>)的实现。其中List<T>就是承担着环境角色,而IComparer<T>接口承担着抽象策略角色,具体的策略角色就是实现了IComparer<T>接口的类,List<T>类本身实现了存在实现了该接口的类,我们可以自定义继承与该接口的具体策略类。

五、 策略者模式的适用场景

在下面的情况下可以考虑使用策略模式:

  1. 一个系统需要动态地在几种算法中选择一种的情况下。那么这些算法可以包装到一个个具体的算法类里面,并为这些具体的算法类提供一个统一的接口。
  2. 如果一个对象有很多的行为,如果不使用合适的模式,这些行为就只好使用多重的if-else语句来实现,此时,可以使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象涉及的概念。

六、 策略者模式的优缺点

优点:

  1. 策略类之间可以自由切换。由于策略类都实现同一个接口,所以使它们之间可以自由切换。
  2. 易于扩展。增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码。
  3. 避免使用多重条件选择语句,充分体现面向对象设计思想。

缺点:

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这点可以考虑使用IOC容器和依赖注入的方式来解决,关于IOC容器和依赖注入(Dependency Inject)的文章可以参考:IoC 容器和Dependency Injection 模式
  2. 策略模式会造成很多的策略类。

七、 总结

到这里,策略模式的介绍就结束了,策略模式主要是对方法的封装,把一系列方法封装到一系列的策略类中,从而使不同的策略类可以自由切换和避免在系统使用多重条件选择语句来选择针对不同情况来选择不同的方法。

转载于:https://www.cnblogs.com/guyun/p/6198062.html

C#设计模式-策略者模式相关推荐

  1. 设计模式--策略(Strategy)模式

    模式定义 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化) 类图 要点总结 Strategy及其子类为组件提供了 ...

  2. Python设计模式-策略模式

    Python设计模式-策略模式 代码基于3.5.2,代码如下; #coding:utf-8 #策略模式class sendInterface():def send(self,value):raise ...

  3. 设计模式之策略者模式

    策略者模式简介 策略者模式定义一个算法接口,并由其实现类去实现,使得每一个算法都得到封装,并让他们可以相互替换.这是一种行为型模式.策略者模式降低了算法行为和环境角色的耦合度,使得算法可以独立发生变化 ...

  4. 关于设计模式——策略模式-Strategy Pattern

    文章目录 1 策略模式 1.1 模拟鸭子 1.2 设计原则 1.3 整合行为 1.4 模拟鸭子代码的代码 1.5 动态设定行为 1.6 重新查看整体 1.7 继承和组合 1.8 总结 1.9 优劣期间 ...

  5. [设计模式] ------ 策略模式

    策略模式 它定义了算法家族,分别封装起来,让他们直接可以互相替换,此模式让算法的变化,不会影响到使用算法的客户 其实很简单,可能很多人都用到了,只不过还不知道这就是策略模式而已. 比如定义一个接口A, ...

  6. java 策略模式 促销_java设计模式——策略模式

    一. 定义与类型 定义:针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换.策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能.当代码中 ...

  7. 设计模式学习笔记——策略(Strategy)模式

    设计模式学习笔记--策略(Strategy)模式 @(设计模式)[设计模式, 策略模式, Stategy] 设计模式学习笔记策略Strategy模式 基本介绍 策略案例 类图 实现代码 Hand类 S ...

  8. 策略设计模式_设计模式之策略者模式

    策略者模式简介 策略者模式定义一个算法接口,并由其实现类去实现,使得每一个算法都得到封装,并让他们可以相互替换.这是一种行为型模式.策略者模式降低了算法行为和环境角色的耦合度,使得算法可以独立发生变化 ...

  9. Springboot 使用设计模式- 策略模式

    前言 直白点,什么场景我们需要使用到设计模式- 策略模式. 在平常的springboot项目里面做CRUD,我们的习惯性基本是 一个mapper,一个service,一个serviceImpl. 但是 ...

最新文章

  1. IEnumerable和IQueryable在使用时的区别
  2. SQL应用中级指南 Part4:(数据字典)
  3. jetty for linux 启用日志
  4. 五、PHP框架Laravel学习笔记——回退、当前路由、单行为
  5. 笔记本cpu温度高怎么办_夏天面团温度高怎么办?几个技巧让面温立马降下来
  6. 电子海图领域一些概念名词的梳理
  7. php用户登录界面代码有背景,HTML和CSS实现动态背景登录页面
  8. 好男07演唱会将开唱 劲歌热舞点燃盛夏激情
  9. B站“崩溃”始末 2021.07.13 我们是这样崩的
  10. SpringMVC 生命周期
  11. DTL(Django templeate language)
  12. 日期插件(默认显示当前日期)---年月
  13. “单向网闸”技术介绍
  14. tp无线路由器设置打印服务器,TP-Link TL-WDR4320 无线路由器打印服务器设置指南
  15. cmd背景颜色设置-cmd白色背景
  16. activiti实现的请假流程
  17. 隐私计算之差分隐私-Laplace机制
  18. linux上namd使用教程,NAMD自学笔记 适用于初学者
  19. 外国月亮也不圆?在硅谷,只有失败者才朝九晚五
  20. 转自科学松鼠会------压缩感知的基础认识

热门文章

  1. 8/7-8/8-8/9 今日TF训练
  2. 06jQuery-06-AJAX
  3. JS判断UA动态加载CSS的方法
  4. openssl生成私钥公钥的步骤
  5. mojoportal升级中用户相关设置
  6. Objective-C超高精度的计时器
  7. 连接impala出现method not supported_Impala在网易大数据的优化和实践
  8. javaweb html5离线存储配置,JavaWeb 知识补充
  9. Python之队列和数据库
  10. (40)System Verilog线程停止(disable fork)