行为型模式(七) 策略模式(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地往返都 ...
随机推荐
- iOS:Xcode代码块,提升敲代码的效率
一.代码块在哪里? 看下图 或者 快捷键:command+shift+L 长这样: 二.如何创建代码块: 1.先选中要创建的代码片段,然后点击右键,选中 Create Code Snippet 然后会 ...
- 在ensp上配置Trunk接口
什么是Trunk接口? 在以太网中,通过划分 VLAN 来隔离广播域和增强网络通信的安全性.以太网通常由多台交换机组成,为了使 VLAN 的数据帧跨越多台交换机传递,交换机之间互连的链路需要设置为干道 ...
- Qt deletelater函数分析(1)
生活的全部意义在于无穷地探索尚未知道的东西,在于不断地增加更多的知识.--左拉 该函数是QObject类的函数: ---- ...
- Mysql中MVCC的使用及原理详解
准备 测试环境:Mysql 5.7.20-log 数据库默认隔离级别:RR(Repeatable Read,可重复读),MVCC主要适用于Mysql的RC,RR隔离级别 创建一张存储引擎为test ...
- 数据结构-二叉树的遍历实现笔记C++
二叉树的遍历实现,可以用递归的方法也可以用非递归的方法.非递归的方法可以借助栈(前序遍历,中序遍历,后序遍历),也可以借助队列(层次遍历).本次笔记只使用了递归的方法来进行前序遍历,中序遍历,后序遍历 ...
- 中国大学MOOC-翁恺-C语言程序设计习题集(二)
04-0. 求符合给定条件的整数集(15)给定不超过6的正整数A,考虑从A开始的连续4个数字.请输出所有由它们组成的无重复数字的3位数. 输入格式: 输入在一行中给出A. 输出格式: 输出满足条件的的 ...
- SpringBoot项目启动不走内嵌容器
一.问题 springboot项目java -jar启动不走内嵌容器,如下图,可以看到是直接走系统环境变量里配置的tomcat容器了 二.分析 我的pom.xml文件关键依赖: <depende ...
- Layui + thymeleaf org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: " 错误解决
解决方法: 1.将layui的代码移动到新的js文件当中,用template模板引擎的方式引入: <script th:src="@{/static/js/facility/mover ...
- Java 哈希表
public int firstUniqChar(String s){ int[] freq=new int[26]; for(int i=0;i<s.length();i++){ freq[s ...
- 直线DDA,直线和圆的Bresenham算法
// DDA.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<Windows.h> #include<g ...