设计模式—策略(Strategy)模式
一、概述
策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化
使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类(ConcreteStrategy)中提供。由于算法和环境独立开来,算法的增减、修改都不会影响环境和客户端。当出现新的促销折扣或现有的折扣政策出现变化时,只需要实现新的策略类,并在客户端登记即可。策略模式相当于"可插入式(Pluggable)的算法"。
二、策略模式的结构
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。"
策略又称做政策(Policy)模式【GOF95】。下面是一个示意性的策略模式结构图:

这个模式涉及到三个角色:
环境(Context)角色:持有一个Strategy类的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
三、 示意性源代码
public abstract class Strategy {abstract public void AlgorithmInterface();
}public class ConcreteStrategyA extends Strategy {// Methods@Overridepublic void AlgorithmInterface() {System.out.print("Called ConcreteStrategyA.AlgorithmInterface()");}
}// "ConcreteStrategyB"
public class ConcreteStrategyB extends Strategy {// Methodspublic void AlgorithmInterface() {System.out.print("Called ConcreteStrategyB.AlgorithmInterface()");}
}// "ConcreteStrategyC"
public class ConcreteStrategyC extends Strategy {// Methods@Overridepublic void AlgorithmInterface() {System.out.print("Called ConcreteStrategyC.AlgorithmInterface()");}
}// "Context"
public class Context {// FieldsStrategy strategy;// Constructorspublic Context(Strategy strategy) {this.strategy = strategy;}// Methodspublic void ContextInterface() {strategy.AlgorithmInterface();}
}/// <summary>
/// Client test
/// </summary>
public class Client {public static void Main(String[] args) {// Three contexts following different strategiesContext c = new Context(new ConcreteStrategyA());c.ContextInterface();Context d = new Context(new ConcreteStrategyB());d.ContextInterface();Context e = new Context(new ConcreteStrategyC());e.ContextInterface();}
}
四、 何时使用何种具体策略角色
在学习策略模式时,学员常问的一个问题是:为什么不能从策略模式中看出哪一个具体策略适用于哪一种情况呢?
答案非常简单,策略模式并不负责做这个决定。换言之,应当由客户端自己决定在什么情况下使用什么具体策略角色。策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中"退休"的方便,策略模式并不决定在何时使用何种算法。
五、 一个实际应用策略模式的例子
下面的例子利用策略模式在排序对象中封装了不同的排序算法,这样以便允许客户端动态的替换排序策略(包括Quicksort、Shellsort和Mergesort)。
abstract class SortStrategy {// Methodspublic abstract void Sort(List<String> list);
}// "ConcreteStrategy"
class QuickSort extends SortStrategy {// Methods@Overridepublic void Sort(List<String> list) {// Default is QuicksortSystem.out.print("QuickSorted list ");}
}// "ConcreteStrategy"
class ShellSort extends SortStrategy {// Methods@Overridepublic void Sort(List<String> list) {//list.ShellSort();System.out.print("ShellSorted list ");}
}// "ConcreteStrategy"
class MergeSort extends SortStrategy {// Methods@Overridepublic void Sort(List<String> list) {//list.MergeSort();System.out.print("MergeSorted list ");}
}// "Context"
class SortedList {// Fieldsprivate List<String> list = new ArrayList<>();private SortStrategy sortstrategy;// Constructorspublic void SetSortStrategy(SortStrategy sortstrategy) {this.sortstrategy = sortstrategy;}// Methodspublic void Sort() {sortstrategy.Sort(list);}public void Add(String name) {list.add(name);}public void Display() {System.out.print(" name");}
}/// <summary>
/// StrategyApp test
/// </summary>
public class StrategyApp {public static void Main(String[] args) {// Two contexts following different strategiesSortedList studentRecords = new SortedList();studentRecords.Add("Samual");studentRecords.Add("Jimmy");studentRecords.Add("Sandra");studentRecords.Add("Anna");studentRecords.Add("Vivek");studentRecords.SetSortStrategy(new QuickSort());studentRecords.Sort();studentRecords.Display();}
}
六、 在什么情况下应当使用策略模式
在下面的情况下应当考虑使用策略模式:
1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2. 一个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。
3. 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和只与算法有关的数据。
4. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。
七、 策略模式的优点和缺点
策略模式有很多优点和缺点。它的优点有:
1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
2. 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
策略模式的缺点有:
1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
相关文章:

设计模式—策略(Strategy)模式
一、概述策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,…...

STM32 触摸屏移植GUI控制控件
目录 1、emWin 支持指针输入设备。 2、 模拟触摸屏驱动 3、实现触摸屏的流程 3.1 实现硬件函数 3.2 实现对GUI_TOUCH_Exec()的定期调用 3.3 使用上一步确定的值,在初始化函数LCD_X_Config()当中添加对GUI_TOUCH_Calibrate()的调用 4、…...

数仓模型之维度建模
目录 1、数仓架构原则 2、如何搭建一个好的数仓 2.1 建模方法 2.2 建模解决的痛点 2.3 数仓系统满足的特性 2.4 数仓架构设计 3、维度建模 4、案例 5、问题讨论 今天我们来聊聊在数仓模型中举足轻重的维度建模。 简单而言,数据仓库的核心目标是为展现层提…...

Servlet笔记(9):Cookie处理
一、Cookies处理 1、Cookies概念 Cookies是存储在客户端计算机上的文本文件,并保留各种跟踪信息。 识别返回用户的三个步骤 服务器脚本向浏览器发送一组Cookies。例如姓名、年龄或识别号码等。浏览器将这些信息存储在本地计算机上。当下一次浏览器向Web服务器发送…...

骨传导耳机是怎么传声的,选择骨传导耳机的时候需要注意什么?
骨传导耳机之所以能够成为当下最火的耳机,骨传导技术将声音转化为震动感,通过骨头进行传播,不会堵塞耳朵,就不会影响到周围环境音。这种技术也让骨传导耳机比传统入耳式耳机更安全,无需入耳式设计,避免了…...

达梦数据库DSC集群部署
一、概述 1.1 DSC 集群架构 1.2 架构说明 1、DMDSC 集群是一个多实例、单数据库的系统。 多个数据库实例可以同时访问、修改同一个数据库的数据。 2、数据文件、控制文件在集群系统中只有一份,不论有几个节点,这些节点都平等地使用这些文件, 这些文件保存在共享存储上。 3…...

java 系列之Mybatis
java 系列文章 文章目录java 系列文章前言一、Mybatis 入门1.1 认识 框架(了解)1.2 认识 ORM(要知道)1.3 认识 Mybatis(要知道)二、Mybatis 使用2.1 创建maven项目并导入依赖2.2 准备数据库,包和…...
OBS 进阶 之 摄像头操作
目录 一、摄像头 1、win-dshow插件中,摄像头枚举操作 1)、视频源ID 2)、注册视频源信息...

Linux操作系统基础知识命令参数详解
Linux操作系统 RAID分组 RAID JBOD RAID JBOD的意思是Just a Bunch Of Disks,是将多块硬盘串联起来组成一个大的存储设备,从某种意义上说这种类型不被算作RAID,在维基百科里JBOD同时也被归入非RAID架构。RAID JBOD将所有的磁盘串联成一个单…...
Rust中一些K/V存储引擎
K/V存储引擎的由来可以追溯到20世纪70年代的Berkley DB,而近年来,随着互联网应用的发展,KV存储引擎因其简单高效、可扩展性和适合缓存应用等特点,在分布式存储领域得到了广泛应用。而使用Rust编写KV存储具有内存安全、高性能、并发…...

202302-第四周资讯
山川软件愿为您提供最优质的服务。 您的每一个疑问都会被认真对待,您的每一个建议都将都会仔细思考。 我们希望人人都能分析大数据,人人都能搭建应用。 因此我们将不断完善我们的DEMO、文档、以及视频,期望能在最大程度上快速帮助用户快速…...

九方财富冲刺上市:付费用户开始减少,退款金额飙升至4.9亿元
日前,九方财富控股有限公司(下称“九方财富”)通过港交所上市聆讯,并披露了聆讯后招股书。据贝多财经了解,九方财富最早于2021年8月31日在港交所递表,后在2022年3月、9月分别进行了更新。 据每日经济新闻报…...

SSM+HTML搭建(小白教学)
最近做项目,觉得还是有意义记录以下前后端框架是怎么搭建的,今天给大家介绍介绍SSM:SpringBootSpringMVCMyBatis后端搭建:SpringBoot快速搭建的网站(Spring Initializr)选择创建之后,会下载到一个zip压缩包,对压缩包进行解压(包地址一般选择后端项目的放的文件夹中)用idea打开项…...

【知识蒸馏】知识蒸馏(Knowledge Distillation)技术详解
参考论文:Knowledge Distillation: A Survey 1.前言 近年来,深度学习在学术界和工业界取得了巨大的成功,根本原因在于其可拓展性和编码大规模数据的能力。但是,深度学习的主要挑战在于,受限制于资源容量࿰…...

公司新招了个腾讯5年经验的测试员,让我见识到什么才是真正的测试天花板····
5年测试,应该是能达到资深测试的水准,即不仅能熟练地开发业务,而且还能熟悉项目开发,测试,调试和发布的流程,而且还应该能全面掌握数据库等方面的技能,如果技能再高些的话,甚至熟悉分…...

(一维、二维)数组传参,(一级、二级)指针传参【含样例分析,新手易懂】
目录数组传参一维数组传参二维数组传参指针传参一级指针传参二级指针传参我们在写代码的时候难免要把数组或者指针传给函数,那函数的参数该如何设计呢? 数组传参 一维数组传参 我们首先来看下面代码的几个例子: #include <stdio.h>…...
for循环中的setTimeout以及var let作用域
看了很多解释,感觉都不好理解。这个文章是我自己的理解,可以做个参考,如果我理解的不对,欢迎在评论区指正: var:使用var声明的变量具有全局作用域 (循环中每次声明的是同一个变量) l…...

有限差分法求解不可压NS方程
网上关于有限差分法解NS方程的程序实现不尽完备,这里是一些补充注解 现有的优秀资料 理论向 【1】如何从物理意义上理解NS方程? - 知乎 【2】NS方程数值解法:投影法的简单应用 - 知乎 【3】[计算流体力学] NS 方程的速度压力法差分格式_…...

Android入门第66天-使用AOP
开篇这篇恐怕又是一篇补足网上超9成关于这个领域实际都是错的、用不起来的一个知识点了。网上太多太多教程和案例用的是一个叫hujiang的AOP组件-com.hujiang.aspectjx:gradle-android-plugin-aspectjx。首先这些错的文章我不知道是怎么来的,其次那些案例真的运行成功…...
pl/sql篇之触发器
简述本文將具体简述触发器的语法,触发条件及其适用场景,希望对读者理解,使用触发器能起到作用。触发器的定位触发器是数据库独立编译,存储的对象,是数据库重要的技术。和函数不同,触发器的执行是主动的&…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...