本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8057654.html,记录一下学习过程以备后续查用。
一、引言
今天我们要讲行为型设计模式的第七个模式--策略模式。在现实生活中,策略模式的例子也非常常见,例如:在一个公司中,会有各种工作人员:有普通员工、有软件架构师、有部门经理,当然也有公司的CEO等等。这些工作人员负责的工作不同、担负的职责也不同,报酬也各不相同。
每种工作人员都有自己的工资,但是不同工种其工资的计算方式是不一样的。如果不采用策略模式来实现这个需求的话,我们可能会这样来做:定义一个工资类,该类有一个属性来标识工作人员的类型,并且有一个计算工资的CalculateSalary()方法,在该方法体内对工作人员类型进行判断,然后通过if-else语句来计算不同类型的工资。这样做确实可以解决这个场景,但是不利于扩展。如果系统后期需要增加一种新的工种时,需对CalculateSalary方法进行修改(再添加一个判断语句),这样明显违背了“开闭原则”。
此时,我们可以考虑使用策略模式来解决这个问题。既然工资计算方法是这个场景中的变化部分,此时自然想到的是对工资算法进行抽象。不同工种的工资可以用不用的策略算法具体实现,若想得到某个工作人员的工资,使用其对应的工资算法策略进行计算就可以了。
二、策略模式介绍
策略模式:英文名称--Strategy Pattern;分类--行为型。
2.1、动机(Motivate)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变。如果将这些算法都编码到对象中,将会使对象变得异常复杂,而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法,将算法与对象本身解耦,从而避免上述问题?
2.2、意图(Intent)
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。——《设计模式》GoF
2.3、结构图(Structure)
2.4、模式的组成
可以看出,在策略模式的结构图有以下角色:
1)环境角色(Context):持有一个Strategy类的引用。
需要使用ConcreteStrategy提供的算法。
内部维护一个Strategy的实例。
负责动态设置运行时Strategy具体的实现算法。
负责跟Strategy之间的交互和数据传递。
2)抽象策略角色(Strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
3)具体策略角色(ConcreteStrategy):实现了Strategy定义的接口,提供具体的算法实现。
2.5、策略模式的具体实现
在现实生活中,策略模式的例子也是很多的,例如:一个公司会有很多工种,每个工种负责的工作不同,其对应的工资计算方法也会不同。我们今天就以工资的计算为例来说明策略模式的使用,实现代码如下:
class Program { /// <summary> /// 环境角色--相当于Context类型 /// </summary> public sealed class SalaryContext { public ISalaryStrategy SalaryStrategy { get; set; } public SalaryContext(ISalaryStrategy strategy) { SalaryStrategy = strategy; } public void GetSalary(double income) { SalaryStrategy.CalculateSalary(income); } } /// <summary> /// 抽象策略角色--相当于Strategy类型 /// </summary> public interface ISalaryStrategy { //工资计算 void CalculateSalary(double income); } /// <summary> /// 程序员的工资--相当于具体策略角色ConcreteStrategyA /// </summary> public sealed class ProgrammerSalary : ISalaryStrategy { public void CalculateSalary(double income) { Console.WriteLine("程序员的工资是:基本工资(" + income + ")底薪(" + 8000 + ")+加班费+项目奖金(10%)"); } } /// <summary> /// 普通员工的工资--相当于具体策略角色ConcreteStrategyB /// </summary> public sealed class NormalPeopleSalary : ISalaryStrategy { public void CalculateSalary(double income) { Console.WriteLine("普通员工的工资是:基本工资(" + income + ")底薪(3000)+加班费"); } } /// <summary> /// CEO的工资--相当于具体策略角色ConcreteStrategyC /// </summary> public sealed class CEOSalary : ISalaryStrategy { public void CalculateSalary(double income) { Console.WriteLine("CEO的工资是:基本工资(" + income + ")底薪(20000)+项目奖金(20%)+公司股票"); } } static void Main(string[] args) { #region 策略模式 //普通员工的工资 SalaryContext context = new SalaryContext(new NormalPeopleSalary()); context.GetSalary(3000); //CEO的工资 context.SalaryStrategy = new CEOSalary(); context.GetSalary(6000); Console.Read(); #endregion } }