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

一、策略模式的使用

1、策略模式定义:

策略模式(Strategy Pattern)定义了一组策略,分别在不同类中封装起来,每种策略都可以根据当前场景相互替换,从而使策略的变化可以独立于操作者。比如我们要去某个地方,会根据距离的不同来选择不同的出行方式,这些出行方式即不同的策略。

个人理解:
就是定义了一个策略接口,然后有多种策略实现类去实现策略接口。

2、何时使用策略模式

阿里开发规约-编程规约-控制语句-第六条 :超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。

相信大家都见过这种代码:


if (conditionA) {逻辑1
} else if (conditionB) {逻辑2
} else if (conditionC) {逻辑3
} else {逻辑4
}

这种代码虽然写起来简单,但是很明显违反了面向对象的2个基本原则:

  • 单一职责原则(一个类应该只有一个发生变化的原因):因为之后修改任何一个逻辑,当前类都会被修改
  • 开闭原则(对扩展开发,对修改关闭):如果此时需要添加(删除)某个逻辑操作,那么就会修改原来的代码

尤其是当if-else 块中的代码量比较大时,后续代码的扩展和维护就会逐渐变得非常困难且容易出错,使用switch 语句也同样避免不了以上两个问题。

比较好的实践:

  • if-else 不超过 2 层,块中代码 1~5 行,直接写到块中,否则封装为方法
  • if-else 超过 2 层,但块中的代码不超过 3 行,尽量使用卫语句
  • if-else 超过 2 层,且块中代码超过 3 行,尽量使用策略模式

3、策略模式实践

在Spring中,如何巧妙的运用策略模式。

3.1、需求背景

我们按照前面说的,我们以去某个地方为由,会根据距离的不同而选择不同的出行方式。

出行的策略(方式):

  • 步行
  • 出租车
  • 地铁

3.2、第一步,定义策略接口

首先定义策略接口,包括两个方法:

  1. 获取策略类型的方法
  2. 处理策略逻辑的方法
public interface ActionHandler {/***	获取策略的类型*/public String actionMethod();/***	处理策略的逻辑*/public Object handler();
}

3.3、第二步,相关策略实现

这里我定义了一个枚举类,用来表示策略的类型及其含义:

public enum ActionMethodEnum {WALK("by_walk","步行"),CAR("by_car","出租车"),SUBWAY("by_subway","地铁"),CYCLE("by_cycle","自行车");private String method;private String desc;ActionMethodEnum(String method,String desc){this.method = method;this.desc = desc;}public String getMethod() {return method;}public String getDesc() {return desc;}
}

步行策略实现类:

@Component
public class ByWalkActionHandler implements ActionHandler {@Overridepublic String actionMethod() {return ActionMethodEnum.WALK.getMethod();}@Overridepublic Object handler() {System.out.println("步行出行。。");return ActionMethodEnum.WALK.getDesc();}
}

出租车策略实现类:

@Component
public class ByCarActionHandler implements ActionHandler {@Overridepublic String actionMethod() {return ActionMethodEnum.CAR.getMethod();}@Overridepublic Object handler() {System.out.println("出租车出行。。。");return ActionMethodEnum.CAR.getDesc();}
}

地铁策略实现类:

@Component
public class BySubwayActionHandler implements ActionHandler {@Overridepublic String actionMethod() {return ActionMethodEnum.SUBWAY.getMethod();}@Overridepublic Object handler() {System.out.println("地铁出行。。。");return ActionMethodEnum.SUBWAY.getDesc();}
}

3.4、建立策略的简单工厂

Tips:
这里使用简单工厂是为了管理我们的策略实现类,将这些策略放入一个Map集合中,后续可以根据策略的类型获取对应的策略处理器。

@Component
public class ActionMethodContext implements InitializingBean, ApplicationContextAware {private ApplicationContext applicationContext;private Map<String, ActionHandler> methodMap = new HashMap<>();/*** 将Spring容器中所有实现了策略接口的类添加到Map集合中 */@Overridepublic void afterPropertiesSet() throws Exception {applicationContext.getBeansOfType(ActionHandler.class).values().stream().forEach(actionHandler -> methodMap.put(actionHandler.actionMethod(),actionHandler));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** 根据出行类型获取对应的策略方法* @param actionMethod* @return*/public ActionHandler getActionMethod(String actionMethod){return methodMap.getOrDefault(actionMethod,new ByWalkActionHandler());}
}

4、使用 & 测试

创建了一个controller来简单的测试:

@RestController
public class ActionController {@AutowiredActionMethodContext actionMethodContext;@GetMapping("/action")public String doAction(String actionMethod){ActionHandler actionHandler = actionMethodContext.getActionMethod(actionMethod);String result = (String) actionHandler.handler();return result;}}

使用postman简单的测试一下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Factory 只负责获取 Handler,Handler 只负责处理具体的提交,Service 只负责逻辑编排,从而达到功能上的 “低耦合高内聚”。

5、扩展

如果我们需要加入一个新的策略,比如自行车出行,我们只需要添加一个新的策略实现即可:

@Component
public class ByCycleActionHandler implements ActionHandler {@Overridepublic String actionMethod() {return ActionMethodEnum.CYCLE.getMethod();}@Overridepublic Object handler() {System.out.println("自行车出行。。。");return ActionMethodEnum.CYCLE.getDesc();}
}

此时不需要修改原有的逻辑,在Spring容器重启时会自动将自行车策略类添加到我们的简单工厂类中。

相关文章:

一、策略模式的使用

1、策略模式定义&#xff1a; 策略模式&#xff08;Strategy Pattern&#xff09;定义了一组策略&#xff0c;分别在不同类中封装起来&#xff0c;每种策略都可以根据当前场景相互替换&#xff0c;从而使策略的变化可以独立于操作者。比如我们要去某个地方&#xff0c;会根据距…...

Verilog使用always块实现时序逻辑

这篇文章将讨论 verilog 中一个重要的结构---- always 块&#xff08;always block&#xff09;。verilog 中可以实现的数字电路主要分为两类----组合逻辑电路和时序逻辑电路。与组合逻辑电路相反&#xff0c;时序电路电路使用时钟并一定需要触发器等存储元件。因此&#xff0c…...

面向对象设计模式:行为型模式之迭代器模式

一、迭代器模式&#xff0c;Iterator Pattern aka&#xff1a;Cursor Pattern 1.1 Intent 意图 Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. 提供一种按顺序访问聚合对象的元素而不公开其基…...

如何快速在企业网盘中找到想要的文件

现在越来越多的企业采用企业网盘来存储文档和资料&#xff0c;而且现在市面上的企业网盘各种各样。在使用企业网盘过程中&#xff0c;很多用户会问到企业网盘中如何快速搜索文件的问题。但是无论是“标签”功能还是普通的“关键词搜索”功能&#xff0c;都是单层级的&#xff0…...

香橙派5使用NPU加速yolov5的实时视频推理(二)

三、将best.onnx转为RKNN格式 这一步就需要我们进入到Ubuntu20.04系统中了&#xff0c;我的Ubuntu系统中已经下载好了anaconda&#xff0c;使用anaconda的好处就是可以方便的安装一些库&#xff0c;而且还可以利用conda来配置虚拟环境&#xff0c;做到环境与环境之间相互独立。…...

算法练习-二分查找(一)

算法练习-二分查找 1 代码实现 1.1 非递归实现 public int bsearch(int[] a, int n, int value) {int low 0;int high n - 1;while (low < high) {int mid (low high) / 2;if (a[mid] value) {return mid;} else if (a[mid] < value) {low mid 1} else {high …...

通用业务平台设计(五):预警平台建设

前言 在上家公司&#xff0c;随着业务的不断拓展(从支持单个国家单个主体演变成支持多个国家多个主体)&#xff0c;对预警的诉求越来越紧迫&#xff1b;如何保障业务的稳定性那&#xff1f;预警可以帮我们提前甄别风险&#xff0c;从而让我们可以在风险来临前将其消灭&#xff…...

Windows openssl-1.1.1d vs2017编译

工具&#xff1a; 1. perl&#xff08;https://strawberryperl.com/&#xff09; 2. nasm&#xff08;https://nasm.us/&#xff09; 3. openssl源码&#xff08;https://www.openssl.org/&#xff09; 可以自己去下载 或者我的网盘提供下载&#xff1a; 链接&#xff1a;…...

【深蓝学院】手写VIO第2章--IMU传感器--笔记

0. 内容 1. 旋转运动学 角速度的推导&#xff1a; 左ω∧\omega^{\wedge}ω∧&#xff0c;而ω\omegaω是在z轴方向运动&#xff0c;θ′[0,0,1]T\theta^{\prime}[0,0,1]^Tθ′[0,0,1]T 两边取模后得到结论&#xff1a; 线速度大小半径 * 角速度大小 其中&#xff0c;对旋转矩…...

网络基础(二)之HTTP与HTTPS

应用层 再谈 "协议" 协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢? 为什么要转换呢&#xff1f; 如果我们将struct message里面的信息…...

Python每日一练(20230306)

目录 1. 翻转二叉树 ★★ 2. 最长公共前缀 ★★ 3. 2的幂 ★ 1. 翻转二叉树 翻转一棵二叉树。 示例 1&#xff1a; 输入&#xff1a; 4/ \2 7/ \ / \ 1 3 6 9 输出&#xff1a; 4/ \7 2/ \ / \ 9 6 3 1示例 2&#xff1a; 输入&#xff1a; 1…...

C/C++每日一练(20230305)

目录 1. 整数分解 ☆ 2. 二叉树的最小深度 ★★ 3. 找x ★★ 1. 整数分解 输入一个正整数&#xff0c;将其按7进制位分解为各乘式的累加和。 示例 1&#xff1a; 输入&#xff1a;49 输出&#xff1a;497^2示例 2&#xff1a; 输入&#xff1a;720 输出&#xff1a;720…...

SAS字典的应用

数据字典中常用信息检索DICTIONARY.COLUMNS、DICTIONARY.TABLES以及DICTIONARY.MEMBERS等字典表的内容。在编程实践中&#xff0c;如何以SAS字典表来提高效率。 1、DICTIONARY.COLUMNS 对于当前SAS任务的全部数据集&#xff0c;表格DICTIONARY.COLUMNS包含了诸如变量的名称、类…...

Mysql中的函数和触发器

函数函数是什么&#xff1f;多用于查询语句&#xff0c;实现了某种功能&#xff1b;用途与存储过程不同&#xff0c;但语法是类似的&#xff1b;函数语法create function 函数名([参数列表]) returns 数据类型 begin DECLARE 变量&#xff1b; sql 语句; return 值; end; 设置函…...

分布式架构之(Zookeeper原理)

Zookeeper是一个典型的分布式数据一致性的结局方案&#xff0c;分布式应用程序可以基于它实现注入数据发布、订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能&#xff0c; Zookeeper可以保证如下分布式一致性特性&#xff1a; 顺…...

Java框架学习 | MyBatis

问题导向学习MyBatis 为什么要有MyBatis框架&#xff1f; 避免Java开发者直接使用 JDBC重复做数据库操作&#xff0c;同时更便捷地实现想要的数据库相关功能&#xff0c;让Java专注于开发业务。 MyBatis框架如何实现该目的&#xff1f; MyBatis是半自动化持久层ORM框架&#x…...

Cookie+Session详解

文章目录批量删除会话技术简介CookieCookie 查看Cookie 的删除Cookie 使用页面获取 cookie 信息cookie 特点Sessionsession 的使用Session 登录权限验证过滤器简介过滤器的使用WebFilter 注解过滤放行登录权限验证批量删除 servlet 类 dao 层 会话技术 简介 在计算机领域…...

CAPL脚本要注意区分elcount和strlen求数组长度的区别,不然要吃大亏

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…...

CSS常用选择器

目录 1.CSS是什么 2.CSS的三种写法 2.1内部样式 2.2内联样式 2.3外部样式 3.CSS选择器 3.1标签选择器 3.2类选择器(更好的选择) 3.3ID选择器 3.4后代选择器 3.5子选择器 3.6并集选择器 3.7伪类选择器(复合选择器的特殊用法) 1.CSS是什么 CSS全称Cascding Style Sh…...

Registry与DGC的攻击利用

0x01 2022-02-03写的一篇文章。 0x02 Registry Registry指的是RMI的注册表&#xff0c;攻击的目标是注册表所在的机器&#xff0c;一般注册表和RMI Server在同一个机器上&#xff0c;特殊情况下也会在不同机器上。 在我们通过LocateRegistry#getRegistry获取到目标开启的注…...

从一次时序违例修复说起:实战中set_multicycle_path与时钟使能(CE)的配合使用指南

从一次时序违例修复说起&#xff1a;实战中set_multicycle_path与时钟使能(CE)的配合使用指南 在FPGA设计流程中&#xff0c;时序收敛往往是最后阶段最令人头疼的问题之一。特别是当设计中使用时钟使能(Clock Enable, CE)信号进行功耗优化时&#xff0c;默认的单周期时序约束可…...

2026免费降AI神器测评:20款国内外工具亲测,哪个真能过检测?

现在写论文&#xff0c;AIGC检测几乎是躲不过的坎。学校用的知网、Turnitin这些系统一直在迭代升级&#xff0c;现在不仅要看重复率&#xff0c;AIGC率也成了硬性考核指标。 熬了好几天改出来的稿子&#xff0c;一查AIGC率居然有90%&#xff0c;换谁心态都得崩&#xff0c;现在…...

intv_ai_mk11 GPU部署教程:A10显卡下intv_ai_mk11服务健康检查脚本编写与自动化监控

intv_ai_mk11 GPU部署教程&#xff1a;A10显卡下intv_ai_mk11服务健康检查脚本编写与自动化监控 1. 环境准备与快速部署 在开始编写健康检查脚本之前&#xff0c;我们需要确保intv_ai_mk11服务已经正确部署在A10显卡服务器上。以下是快速部署步骤&#xff1a; 系统要求&#…...

突破平台壁垒:探索5种在Windows运行Android应用的实战方案与终极选择

突破平台壁垒&#xff1a;探索5种在Windows运行Android应用的实战方案与终极选择 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 在数字化办公与娱乐深度融合的今天&am…...

ML.NET + 1-bit LLM:在 C# 上位机实现仅 1GB 内存的本地 AI 推理

文章目录上位机程序员的内存焦虑&#xff0c;谁懂啊1-bit LLM是个啥&#xff1f;把模型"压缩裤"穿到极致ML.NET&#xff1a;被遗忘的.NET AI利器实战&#xff1a;把BitNet塞进你的上位机路子一&#xff1a;ONNX Runtime桥梁&#xff08;最正统&#xff09;路子二&…...

Geoserver空间查询全解析:从基础bbox到高级CQL_FILTER的完整指南

Geoserver空间查询全解析&#xff1a;从基础bbox到高级CQL_FILTER的完整指南 当你面对海量地理空间数据时&#xff0c;如何快速准确地提取所需信息&#xff1f;Geoserver作为开源地理信息系统&#xff08;GIS&#xff09;的中枢神经&#xff0c;其强大的空间查询能力往往被开发…...

Krita AI Diffusion图像引导适配器功能异常的深度解决方案

Krita AI Diffusion图像引导适配器功能异常的深度解决方案 【免费下载链接】krita-ai-diffusion Streamlined interface for generating images with AI in Krita. Inpaint and outpaint with optional text prompt, no tweaking required. 项目地址: https://gitcode.com/gh…...

League Akari:英雄联盟玩家的终极智能工具箱 - 3大核心功能深度解析

League Akari&#xff1a;英雄联盟玩家的终极智能工具箱 - 3大核心功能深度解析 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power &#x1f680;. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄联盟…...

终极指南:3步打造你的闲鱼AI客服机器人,实现24小时自动化值守

终极指南&#xff1a;3步打造你的闲鱼AI客服机器人&#xff0c;实现24小时自动化值守 【免费下载链接】XianyuAutoAgent 智能闲鱼客服机器人系统&#xff1a;专为闲鱼平台打造的AI值守解决方案&#xff0c;实现闲鱼平台724小时自动化值守&#xff0c;支持多专家协同决策、智能议…...

Qwen3-VL-30B部署避坑指南:从下载到运行一气呵成

Qwen3-VL-30B部署避坑指南&#xff1a;从下载到运行一气呵成 1. 为什么选择Qwen3-VL-30B Qwen3-VL-30B是目前通义千问系列中最强大的视觉-语言模型&#xff0c;它在多个方面实现了显著提升&#xff1a; 更优秀的文本理解和生成&#xff1a;能够处理复杂语义和长文本更深入的…...