行为型模式(七) 策略模式(Stragety)
一、动机(Motivate)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
二、意图(Intent)
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。 ——《设计模式》GoF
三、结构图(Structure)

四、模式的组成
可以看出,在策略模式的结构图有以下角色:
(1)、环境角色(Context):持有一个Strategy类的引用。
需要使用ConcreteStrategy提供的算法。
内部维护一个Strategy的实例。
负责动态设置运行时Strategy具体的实现算法。
负责跟Strategy之间的交互和数据传递
(2)、抽象策略角色(Strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
(3)、具体策略角色(ConcreteStrategy):实现了Strategy定义的接口,提供具体的算法实现。
五、策略模式的代码实现
在现实生活中,策略模式的例子也是很多的,例如:一个公司会有很多工作种类,每个工作种类负责的工作不同,自然每个工种的工资计算方法也会有千差万别,我们今天就以工资的计算为例来说明策略模式的使用,我们直接上代码,但是实际编码中切记别这样,我们要通过迭代的方式使用模式。实现代码如下:
public static void Main(String[] args)
{
//普通员工的工资
SalaryContext context = new SalaryContext(new NormalPeopleSalary());
context.GetSalary(3000); //CEO的工资
context.ISalaryStrategy = new CEOSalary();
context.GetSalary(6000); Console.Read();
}
//环境角色---相当于Context类型
public sealed class SalaryContext
{
private ISalaryStrategy _strategy; public SalaryContext(ISalaryStrategy strategy)
{
this._strategy = strategy;
} public ISalaryStrategy ISalaryStrategy
{
get { return _strategy; }
set { _strategy = value; }
} public void GetSalary(double income)
{
_strategy.CalculateSalary(income);
}
} //抽象策略角色---相当于Strategy类型
public interface ISalaryStrategy
{
//工资计算
void CalculateSalary(double income);
} //程序员的工资--相当于具体策略角色ConcreteStrategyA
public sealed class ProgrammerSalary : ISalaryStrategy
{
public void CalculateSalary(double income)
{
Console.WriteLine("我的工资是:基本工资(" + income + ")底薪(" + 8000 + ")+加班费+项目奖金(10%)");
}
} //普通员工的工资---相当于具体策略角色ConcreteStrategyB
public sealed class NormalPeopleSalary : ISalaryStrategy
{
public void CalculateSalary(double income)
{
Console.WriteLine("我的工资是:基本工资(" + income + ")底薪(3000)+加班费");
}
} //CEO的工资---相当于具体策略角色ConcreteStrategyC
public sealed class CEOSalary : ISalaryStrategy
{
public void CalculateSalary(double income)
{
Console.WriteLine("我的工资是:基本工资(" + income + ")底薪(20000)+项目奖金(20%)+公司股票");
}
}
六、策略模式的实现要点:
Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换,所谓封装算法,支持算法的变化。Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
与State类似,如果Strategy对象没有实例变量,那么各个上下文可以共享一个Strategy对象,从而节省对象开销。Strategy模式适用的是算法结构中整个算法的改变,而不是算法中某个部分的改变。
- Template Method方法:执行算法的步骤协议是本身放在抽象类里面的,允许一个通用的算法操作多个可能实现
- Strategy模式:执行算法的协议是在具体类,每个具体实现有不同通用算法来做。
1、策略模式的主要优点有:
1】、策略类之间可以自由切换。由于策略类都实现同一个接口,所以使它们之间可以自由切换。
2】、易于扩展。增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码。
3】、避免使用多重条件选择语句,充分体现面向对象设计思想。
2、策略模式的主要缺点有:
1】、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这点可以考虑使用IOC容器和依赖注入的方式来解决,关于IOC容器和依赖注入(Dependency Inject)的文章可以参考:IoC 容器和Dependency Injection 模式。
2】、策略模式会造成很多的策略类。
3、在下面的情况下可以考虑使用策略模式:
1】、一个系统需要动态地在几种算法中选择一种的情况下。那么这些算法可以包装到一个个具体的算法类里面,并为这些具体的算法类提供一个统一的接口。
2】、如果一个对象有很多的行为,如果不使用合适的模式,这些行为就只好使用多重的if-else语句来实现,此时,可以使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象涉及的概念。
七、.NET 策略模式的实现
在.NET Framework中也不乏策略模式的应用例子。例如,在.NET中,为集合类型ArrayList和List<T>提供的排序功能,其中实现就利用了策略模式,定义了IComparer接口来对比较算法进行封装,实现IComparer接口的类可以是顺序,或逆序地比较两个对象的大小,具体.NET中的实现可以使用反编译工具查看List<T>.Sort(IComparer<T>)的实现。其中List<T>就是承担着环境角色,而IComparer<T>接口承担着抽象策略角色,具体的策略角色就是实现了IComparer<T>接口的类,List<T>类本身实现了存在实现了该接口的类,我们可以自定义继承与该接口的具体策略类。
行为型模式(七) 策略模式(Stragety)的更多相关文章
- 大型Java进阶专题(七) 设计模式之委派模式与策略模式
前言 今天开始我们专题的第七课了.本章节将介绍:你写的代码中是否觉得很臃肿,程序中有大量的if...else,想优化代码,精简程序逻辑,提升代码的可读性,这章节将介绍如何通过委派模式.策略模式让你 ...
- Android设计模式之命令模式、策略模式、模板方法模式
命令模式是其它很多行为型模式的基础模式.策略模式是命令模式的一个特例,而策略模式又和模板方法模式都是算法替换的实现,只不过替换的方式不同.下面来谈谈这三个模式. 命令模式 将一个请求封装为一个对象,从 ...
- Provider Pattern提供者模式和策略模式
http://www.codeproject.com/Articles/18222/Provider-Pattern Introduction Provider pattern is one of t ...
- 我学的是设计模式的视频教程——命令模式vs策略模式,唠嗑
课程视频 命令模式vs策略模式 唠嗑 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 版权声明:本文博主原创文章,博客,未经同意不得转载.
- 模式PK:命令模式VS策略模式
1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为“算法”已经是一个 ...
- ES6对抽象工厂模式与策略模式结合的实践
这段代码是我在学习了java版的抽象工厂模式后,实现的ES6版抽象工厂,后期大幅修改,加入了策略模式,看起来很多逻辑看似繁琐,不必要写这么多,但是为了练习设计模式,所以才这样做.当所需的工厂种类增多后 ...
- C++模式学习------策略模式
当遇到同一个对象有不同的行为,方法,为管理这些方法可使用策略模式. 策略模式就是对算法进行包装,是把使用算法的责任和算法本身分割开来.通常把一个系列的算法包装到一系列的策略类里面,这些类继承一个抽象的 ...
- 【设计模式】 模式PK:命令模式VS策略模式
1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为“算法”已经是一个 ...
- 策略模式、策略模式与Spring的碰撞
策略模式是GoF23种设计模式中比较简单的了,也是常用的设计模式之一,今天我们就来看看策略模式. 实际案例 我工作第三年的时候,重构旅游路线的机票查询模块,旅游路线分为四种情况: 如果A地-B地往返都 ...
随机推荐
- springboot统一返回json数据格式并配置系统异常拦截
本文链接:https://blog.csdn.net/syystx/article/details/82870217通常进行前后端分离开发时我们需要定义统一的json数据交互格式并对系统未处理异常进行 ...
- python断点
pycharm怎么debug单步调试 1.打开一个Pycharm的界面,需要选中编辑器中的左侧. 2.点击Run---->Debug运行 3.点击箭头,向下运行 4.可以看到代码运行到下一条 5 ...
- 采用socket传输文件
采用socket传输文件 客户端输入文件的地址,服务端判断文件存在,就将文件传输到客户端 package com.fly.socket; import java.io.BufferedInputStr ...
- Java开发笔记(一百一十七)AWT窗口
前面介绍的所有Java代码,都只能通过日志观察运行情况,就算编译成class文件,也必须在命令行下面运行,这样的程序无疑只能给开发者做调试用,不能拿给一般人使用.因为普通用户早已习惯在窗口界面上操作, ...
- Java开发笔记(一百二十九)Swing的输入框
Swing的输入框仍然分成两类:单行输入框和多行输入框,但与AWT的同类控件相比,它们在若干细节上有所调整.首先说单行输入框,AWT的单行输入框名叫TextField,平时输入什么字符它便显示什么字符 ...
- pandas再次学习
numpy.scipy官方文档 pandas官方网站 matplotlib官方文档 一.数据结构 二.数据处理 1.数据获取(excel文件数据基本信息) #coding=utf-8 import ...
- springboot项目 配置https
感谢 https://www.jianshu.com/p/1b7b9e0803c6 帮我解决了问题 生成自签名证书 keytool -genkey -storetype PKCS12 -keysiz ...
- 微软.NET CORE 3.0 预览版 7 发布:大幅减少 SDK 空间大小
据悉,这个预览版是 .Net Core 3 中重要的版本,可以视为原计划在 7 月发布的 RC 版本 (引自微软 .NET Core 首席 Program Manager Richard 先生原话), ...
- Java 二叉搜索树 实现和学习
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> ...
- iOS - 安装CocoaPods详细过程(重装系统后!)
重装的系统,发现很多东西都要重装,顺便复习和检验下以前的方法还有没有效 一.简介 什么是CocoaPods CocoaPods是OS X和iOS下的一个第三类库管理工具,通过CocoaPods工具我们 ...