设计模式~策略模式
策略模式属于对象的行为模式。
其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
策略模式使得算法可以在不影响到客户端的情况下发生变化。
策略模式相当于可插入式的算法。
当准备在一个系统里使用策略模式时,首先必须找到需要包装的算法,看看算法是否可以从环境中分割开来,
最后在考察这些算法是否会在以后发生变化。
策略模式的结构
这个模式涉及三个角色:
- 环境角色(Context): 持有一个Strategy类的引用。
- 抽象策略角色(Strategy): 这是一个抽象角色,通常由一个接口或抽象类实现。
- 具体策略角色(ConcreteStrategy): 包装了相关的算法或行为。
源代码:
环境类
public class Context {
private Strategy strategy;
//策略方法
public void contextInterface(){
strategy.strategyInterface();
}
}
抽象策略类
public abstract class Strategy {
//策略方法
public abstract void strategyInterface();
}
具体策略类
public class ConcreteStrategy extends Strategy {
//策略模式
@Override
public void strategyInterface() {
//write your algorithm code here
}
}
这里给出的仅仅是策略模式的最小实现,因此具体策略角色才只有一个。
一般而言,有意义的策略模式的应用都会涉及到多于一个的具体策略角色。
模式的实现
策略模式实现要注意的地方:
1. 经常见到的是,所有具体的策略类都有一些公关的方法。这时候,就应当把这些公关的行为放到共同的抽象角色Strategy类里面。当然这时候抽象策略角色必须要用java抽象类实现,而不能是java接口。
2. 策略模式在每一个时刻都只能使用一个策略对象,但是有的时候一个应用程序同时和几个策略对象相联系。
也就是说,在应用程序启动时,所有的策略对象就已经被创立出来,而应用程序可以在几个策略对象之间调换。
Java语言内部的例子
AWT中的LayoutManager
java.awt类库需要在运行期间动态的由客户端决定一个Container对象怎样排列它所有的GUI构件。
Java语言提供了几种不同的排序方式,包装在不同的类里:
- BorderLayout
- FlowLayout
- GridLayout
- GridBagLayout
- CardLayout
LayoutManager的类图:
排序策略系统
假设要设计一个排序系统,动态的决定采用二元排序(Binary Sort)、泡沫排序(Bubble Sort)、堆栈排序(Heap Sort)、
快速排序(Quick Sort)、基数排序(Radix Sort)。
显然,采用策略模式把几种排序算法包装到不同的算法类里面,让所有的算法类具有相同的接口,就是一个很好的设计。
排序策略系统的设计如下:
客户端必须决定在何时使用哪一个排序算法,也就是所,这个决定不是在模式内部决定的。
另外,策略模式不适合于处理同事嵌套多于一个算法的情形。
一般而言,策略模式只适用于客户端在几种算法中选择一种的情形,并不适用于客户端同时需要几种算法的情形。
例如,算法四,在所有的折扣算法计算后,总的折扣数不能超过1000.
这就意味着客户端必须首先适用折扣算法一、二、三计算出折扣总值后,再使用算法四。
这种重复使用多种算法的情形不是单纯的策略模式可以处理的,需要进一步使用装饰模式。
在什么情况下使用策略模式
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态的让一个对象在许多行为中选择一种行为。
- 一个系统需要动态的在几种算法中选择一种。
- 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的知识和只与算法有关的数据。
- 如果一个对象有很多行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。
策略模式的优点和缺点
优点:
- 策略模式提供了管理相关算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移动到父类里面,从而避免重复的代码。
- 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不用策略模式,那么使用算法或行为的环境类就可能会有一些资料,每一个子类提供一个不同的算法或行为。但是,这样一来,算法或行为的使用者就和算法或行为的本身混在了一起。决定使用哪种算法和采取哪种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立的演化。继承使得动态改变算法或行为变得不可能。
- 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。也就是说,策略模式只适用于客户端知道所有算法或行为的情况。
- 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同的客户端使用。也就是说,可以使用享元模式来减少对象的数量。
- Django--admin源码流程
- Spring Security笔记:Remember Me(下次自动登录)
- day8、 显示Linux路由表、各列信息
- day9、用户登陆出现-bash-4.1$错误的原因及解决方法
- jboss eap 6.3 域(Domain)模式配置
- 揭穿数据分析的12个神话
- jboss eap 6.3 集群(cluster)配置
- Django中Q查询及Q()对象
- jboss eap 6.3 集群(cluster)-Session 复制(Replication)
- JSP中的Servlet及Filter
- Django ORM详解
- Web前端培训:怎样成长为一个优秀的Web 前端开发工程师?
- Git操作
- 人工智能做的肉,你想吃吗?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R语言广义线性模型索赔频率预测:过度分散、风险暴露数和树状图可视化
- 还在使用Future轮询获取结果吗?CompletionService快来了解下。
- R语言通过伽玛与对数正态分布假设下的广义线性模型对大额索赔进行评估预测
- R语言精算学:使用链梯法Chain Ladder和泊松定律模拟和预测未来赔款数据
- 微服务[学成在线] day19:分布式事务
- 微服务[学成在线] day20:项目部署与持续集成(DevOps)
- R语言中回归模型预测的不同类型置信区间应用比较分析
- R语言进阶之坐标轴和文本
- R语言广义线性模型(GLM)广义相加模型(GAM):多元平滑回归分析保险投资风险敞口
- 面试高频题:springBoot自动装配的原理你能说出来吗?
- R语言巨灾风险下再保险合同定价研究案例:广义线性模型和帕累托分布分析
- nodejs搭建mqtt服务器
- R语言中GLM(广义线性模型),非线性和异方差可视化分析
- 解决java的http请求库dongliu.requests请求结果中文乱码的问题
- 保姆级教程,手把手教你实现一个SpringBoot的starter