当前位置: 首页 > news >正文

【设计模式】策略模式定义及其实现代码示例

文章目录

    • 一、策略模式
      • 1.1 策略模式的定义
      • 1.2 策略模式的参与者
      • 1.3 策略模式的优点
      • 1.4 策略模式的缺点
      • 1.5 策略模式的使用场景
    • 二、策略模式简单实现
      • 2.1 案例描述
      • 2.2 实现代码
    • 三、策略模式的代码优化
      • 3.1 优化思路
      • 3.2 抽象策略接口
      • 3.3 上下文
      • 3.4 具体策略实现类
      • 3.5 测试
    • 参考资料

完整案例代码:java-demos/design-pattern-demos/strategy-pattern at main · idealzouhu/java-demos

一、策略模式

1.1 策略模式的定义

策略模式(Strategy Pattern)定义如下:

Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)

1.2 策略模式的参与者

策略模式的参与者主要有:

  • Context(上下文类):它持有一个 Strategy 对象,用于调用具体策略的方法。客户端通常只需要与 Context 交互,而不直接接触具体的策略实现
  • Strategy(策略接口):定义了算法的通用接口,所有具体策略都实现这个接口。
  • ConcreteStrategy(具体策略类):实现 Strategy 接口的具体算法类,不同的策略类提供不同的算法实现。

1.3 策略模式的优点

  • 避免使用多重条件判断:策略模式可以取代if-elseswitch-case的条件分支。

1.4 策略模式的缺点

  • 策略数量可能会增多:如果策略太多,会增加类的数量,维护成本上升。如果 if-else 判断分支不多并且是固定的,那就使用策略模式即可。

1.5 策略模式的使用场景

  • 算法/行为自由切换: 比如支付系统中,可以通过策略模式动态选择不同的支付方式(微信支付、支付宝支付、信用卡支付等)。
  • 屏蔽算法底层细节:只用知道算法名字即可

二、策略模式简单实现

2.1 案例描述

假设我们有一个系统,它可以根据不同的需求选择不同的排序算法,比如快速排序、冒泡排序、归并排序等。通过策略模式,我们可以将这些不同的算法作为策略类进行实现。

2.2 实现代码

// 策略接口
interface SortStrategy {void sort(int[] array);
}// 具体策略类:快速排序
class QuickSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 快速排序算法实现System.out.println("Using Quick Sort");// 排序逻辑}
}// 具体策略类:冒泡排序
class BubbleSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 冒泡排序算法实现System.out.println("Using Bubble Sort");// 排序逻辑}
}// 上下文类:负责使用策略
class SortingContext {private SortStrategy strategy;// 设置策略public void setStrategy(SortStrategy strategy) {this.strategy = strategy;}// 执行排序public void executeSort(int[] array) {strategy.sort(array);}
}// 测试
public class StrategyPatternExample {public static void main(String[] args) {SortingContext context = new SortingContext();// 使用快速排序策略context.setStrategy(new QuickSortStrategy());context.executeSort(new int[]{3, 1, 2});// 使用冒泡排序策略context.setStrategy(new BubbleSortStrategy());context.executeSort(new int[]{3, 1, 2});}
}

三、策略模式的代码优化

3.1 优化思路

优化思路为使用 @Component 修饰具体策略类,从而让 Spring 提供的 IoC 容器自动添加策略类,从而实现开闭原则。

注意事项,如果你的策略实现类被初始化的时间晚于 onApplicationEvent 方法的调用,可能会导致在注册策略时未能找到这些策略。确保所有策略组件在 onApplicationEvent 被调用之前已经被创建和注册。

3.2 抽象策略接口

AbstractExecuteStrategy 定义了一个策略执行的基本框架,供具体策略类实现。主要方法有:

  • mark():默认返回策略标识的字符串,可以被具体策略类重写以返回唯一标识。
  • patternMatchMark():用于模式匹配的标识,允许根据一定模式选择策略。
  • execute(REQUEST requestParam):执行策略的方法,接受一个请求参数,默认实现为空,具体策略类可以重写。
  • executeResp(REQUEST requestParam):执行策略并返回结果的方法,接受请求参数并返回响应,默认实现返回null,具体策略类可以重写。
/*** 策略执行抽象接口**/
public interface AbstractExecuteStrategy<REQUEST, RESPONSE>  {/*** 执行策略标识* 用于标识具体的执行策略**/default String mark() {return null;}/*** 执行策略范匹配标识* 用于在多个策略中通过模式匹配选择合适的策略执行**/default String patternMatchMark() {return null;}/*** 执行策略** @param requestParam 执行策略所需的参数,类型为REQUEST*/default void execute(REQUEST requestParam) {}/*** 执行策略,带有返回值** @param requestParam 执行策略所需的参数,类型为REQUEST* @return 执行策略后返回值,类型为RESPONSE*/default RESPONSE executeResp(REQUEST requestParam) {return null;}
}

3.3 上下文

AbstractStrategyChoose 类用于管理和选择具体的策略,并执行对应的策略。主要方法有:

  • choose(String mark, Boolean predicateFlag):如果predicateFlag为true,则进行模式匹配选择策略。如果predicateFlag为false,则直接根据 mark 查询策略。

  • chooseAndExecute(String mark, REQUEST requestParam)

    根据标识选择策略并执行,调用对应的execute方法。

  • chooseAndExecute(String mark, REQUEST requestParam, Boolean predicateFlag):根据标识和模式匹配标识选择策略并执行。

  • onApplicationEvent(ApplicationInitializingEvent event):实现ApplicationListener接口,当Spring应用初始化时,自动注册所有的AbstractExecuteStrategy实现类

3.4 具体策略实现类

@Component
public class AddStrategy  implements AbstractExecuteStrategy<Integer, Integer> {@Overridepublic String mark() {return "ADD";}@Overridepublic Integer executeResp(Integer requestParam) {return requestParam + 10; // 假设每次加10}}

3.5 测试

@SpringBootTest
class StrategyPatternApplicationTests {@Autowiredprivate AbstractStrategyChoose strategyChoose;@Testvoid testAddStrategy() {// 测试加法策略Integer addResult = strategyChoose.chooseAndExecuteResp("ADD", 20);System.out.println("Add Strategy Result: " + addResult); // 期望结果:30assertEquals(Integer.valueOf(30), addResult);}
}

参考资料

Java设计模式之策略模式(UML类图分析+代码详解)

12306: 完成高仿铁路 12306 用户 + 抢票 + 订单 + 支付服务

相关文章:

【设计模式】策略模式定义及其实现代码示例

文章目录 一、策略模式1.1 策略模式的定义1.2 策略模式的参与者1.3 策略模式的优点1.4 策略模式的缺点1.5 策略模式的使用场景 二、策略模式简单实现2.1 案例描述2.2 实现代码 三、策略模式的代码优化3.1 优化思路3.2 抽象策略接口3.3 上下文3.4 具体策略实现类3.5 测试 参考资…...

list与iterator的之间的区别,如何用斐波那契数列探索yield

问题 list与iterator的之间的区别是什么&#xff1f;如何用斐波那契数列探索yield&#xff1f; 2 方法 将数据转换成list,通过对list索引和切片操作&#xff0c;以及可以进行添加、删除和修改元素。 iterator是一种对象&#xff0c;用于遍历可迭代对象&#xff08;如列表、元组…...

抖音店铺数据也就是抖店,如何使用小店数据集来挖掘价值?

​ 抖音商家现在基本达到二百多万家抖店&#xff0c;有一些公司可能会根据开放的数据研究行业分布、GMV等等&#xff0c;就像是也出了专业的一些平台如“蝉妈妈”、“达多多”&#xff0c;对我来说受限制就是难受。 当然也有很多大型合法的数据平台有抖店数据集&#xff0c;但…...

KubeVirt 安装和配置 Windows虚拟机

本文将将介绍如何安装 KubeVirt 和使用 KubeVirt 配置 Windows 虚拟机。 前置条件 准备 Ubuntu 操作系统&#xff0c;一定要安装图形化界面。 安装 Docker&#xff08;最新版本&#xff09; 安装 libvirt 和 TigerVNC&#xff1a; apt install libvirt-daemon-system libvir…...

CM API方式设置YARN队列资源

简述 对于CDH版本我们可以参考Fayson的文章,本次是CDP7.1.7 CM7.4.4 ,下面只演示一个设置队列容量百分比的示例,其他请参考cloudera官网。 获取cookies文件 生成cookies.txt文件 curl -i -k -v -c cookies.txt -u admin:admin http://192.168.242.100:7180/api/v44/clusters …...

Mysql常用语法一篇文章速成

文章目录 前言前置环境数据库的增删改查查询数据查询所有条件查询多条件查询模糊查询分页查询排序查询分组查询⭐️⭐️关联查询关联分页查询 添加数据insert插入多条记录不指定列名(适用于所有列都有值的情况) 更新数据更新多条记录更新多个列更新不满足条件的记录 删除统计数…...

Intel nuc x15 重装系统步骤和注意事项(LAPKC71F、LAPKC71E、LAPKC51E)

注意本教程的对象是11代CPU&#xff0c;英伟达独显的nuc x15&#xff0c;不是12代arc显卡的。 x15安装win11 24h2&#xff0c;如果在装系统时联网&#xff0c;windows自动下载的最新驱动有兼容问题&#xff0c;会导致【英特尔显卡控制中心】装不上&#xff0c;或者【英特尔nuc…...

Linux之实战命令59:iwlist应用实例(九十三)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…...

数据库_SQLite3

下载 1、更新软件源&#xff1a; sudo apt-get update 2、下载SQLite3&#xff1a; sudo apt-get install sqlite3 3、验证&#xff1a; sqlite3启动数据库&#xff0c;出现以下界面代表运行正常。输入 .exit 可以退出数据库 4、安装sqlite3的库 sudo apt-get install l…...

.Net Framework里演示怎么样使用StringBuilder、Math.Min和String.Format

StringBuilder、Math.Min和String.Format, 这几个功能都是我们经常使用的功能, 但是怎么样正确地使用,还是得向微软的开发人员学习。 他们在写.Net Framework的源码时,就会大量使用。 因此,我们可以多看看这分代码,就可以理解他们怎么样使用的。 他们的使用方式,一…...

Oracle创建存储过程,创建定时任务

在Oracle数据库中&#xff0c;创建存储过程和定时任务&#xff08;也称为调度任务&#xff09;是常见的数据库管理任务。以下是创建存储过程和定时任务的步骤和说明。 创建存储过程 创建存储过程的sql脚本 create or replace procedure 存储过程名称... is begin脚本逻辑...…...

<HarmonyOS第一课>应用/元服务上架的课后习题

善者&#xff0c;吾善之&#xff1b; 不善者&#xff0c;吾亦善之&#xff0c;德善。 信者&#xff0c;吾信之&#xff1b; 不信者&#xff0c;吾亦信之&#xff0c;德信。 圣人在天下&#xff0c;歙歙焉为天下浑其心&#xff0c;百姓皆注其耳目&#xff0c;圣人皆孩之。 通过&…...

【Python】探索函数的奥秘:从基础到高级的深度解析(下)

目录 &#x1f354; 函数的参数进阶 1、函数的参数 2、函数的参数类型(调用) 2.1 位置参数 2.2 关键词参数&#xff08;Python特有&#xff09; 3、函数定义时缺省参数&#xff08;参数默认值&#xff09; 4、不定长参数 4.1 不定长元组&#xff08;位置&#xff09;参数…...

ima.copilot:智慧因你而生

在数字化时代&#xff0c;信息的获取、处理和创作已经成为我们日常工作和学习中不可或缺的一部分。腾讯公司推出的ima.copilot&#xff08;简称ima&#xff09;正是为了满足这一需求&#xff0c;它是一款由腾讯混元大模型提供技术支持的智能工作台产品&#xff0c;旨在通过智能…...

Vue-$el属性

原博客地址&#xff1a;深入 Vue.js 的心脏&#xff1a;全面剖析 $el 属性_vue $el-CSDN博客 目录 1 $el是什么 1.1 $el本质 1.2 访问$el时机 1.3 $el与模板的关系 2 $el使用场景 2.1 集成第三方库 2.2 操作DOM元素样式 2.3 处理焦点和事件 2.4 实现自定义指令 3 $e…...

LLC Power Switches and Resonant Tank 笔记

1.概述 上面是一个典型的LLC电路。注意Lm是励磁电感&#xff0c;就是次级线圈空载时的主变压器电感&#xff0c;据说在计算谐振频率时无需关心。然后&#xff0c;作为DCDC电源&#xff0c;它通过调整谐振频率&#xff0c;来改变输出的电流。负载越大&#xff0c;频率越低&#…...

Python 如何在 Web 环境中使用 Matplotlib 进行数据可视化

Python Matplotlib 在 Web 环境中的可视化 数据可视化是数据科学和分析中一个至关重要的部分&#xff0c;它能帮助我们更好地理解和解释数据。在现代应用中&#xff0c;越来越多的开发者希望能够将数据可视化结果展示在网页上。Matplotlib 是 Python 中最常用的数据可视化库之…...

C#-数组:一维数组、二维数组、交错数组

数组&#xff1a;声明初始化过后&#xff0c;就不能在原有的基础上进行 添加 或者 删除 了 一&#xff1a;一维数组 一般将一维数组简称为数组 1.1 数组的声明 int[] arr1; 没有分配房间。初始化后就分配房间了int[] arr2 new int[5]; 存在默认值&#xff0c;为0int[] arr3…...

动态规划应该如何学习?

动态规划如何学习 参考灵神的视频和题解做的笔记&#xff08;灵神YYDS&#xff0c;以后也都会用这套逻辑去思考&#xff09; 枚举选哪个&#xff1a; 动态规划入门&#xff1a;从记忆化搜索到递推_哔哩哔哩_bilibili 746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&a…...

【力扣 + 牛客 | SQL题 | 每日4题】牛客SQL热题210,213,212,219

1. 力扣SQL1076&#xff1a;项目员工2 1.1 题目&#xff1a; 表&#xff1a;Project ---------------------- | Column Name | Type | ---------------------- | project_id | int | | employee_id | int | ---------------------- (project_id, employee_id) 是…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...

Mac flutter环境搭建

一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...

精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑

精益数据分析&#xff08;98/126&#xff09;&#xff1a;电商转化率优化与网站性能的底层逻辑 在电子商务领域&#xff0c;转化率与网站性能是决定商业成败的核心指标。今天&#xff0c;我们将深入解析不同类型电商平台的转化率基准&#xff0c;探讨页面加载速度对用户行为的…...

PLC入门【4】基本指令2(SET RST)

04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C)&#xff0c;从 文件 - 主画面&#xff0c;“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…...