Java设计模式——策略
前言
策略模式是平时Java开发中常用的一种,虽然已有很多讲解设计模式的文章,但是这里还是写篇文章来从自己理解的角度讲解一下。
使用场景
我们不妨进行场景假设,要对我们的软件进行授权管理:在启动我们的软件之前先要校验是否存在合法的授权,如果授权不合法则要求用户进行激活操作。作为例子,我们就简单地实现一下授权校验功能:分发的授权文件中内容是一个四位随机数,并且最后一位是数字且为0。我们只要校验授权文件中内容的最后一位是数字0即可。
public class LicenseService {public boolean checkLicense() {boolean result = false;// abc0File file = Path.of("./secret").toFile();String content = "";try{// 读取文件内容BufferedReader br = new BufferedReader(new FileReader(file));content = br.readLine();br.close();}catch(Exception e){e.printStackTrace();}// 末尾字符是0即认为校验通过if (content.endsWith("0")) {result = true;}return result;}
}
需求变更
现在需求进行了变更,不再校验末尾字符为0了,而是校验开头字符是0,因此我们需要对程序进行修改。并且,我们在调整程序的过程中将读取文件内容和授权校验的逻辑进行分离,将授权校验的逻辑抽到一个单独的方法中。
public boolean checkLicense() {...result = checkInternal(content, result);...}private static boolean checkInternal(String content, boolean result) {if (content.startsWith("0")) {result = true;}return result;}
改完之后又接到了最新通知,还有可能改回原来末尾字符的判断方式,于是我们又对方法进行了调整。通过方法传入一个参数来决定使用哪种方式判断:
public boolean checkLicense() {...result = checkInternal(content, result, 1);...}private static boolean checkInternal(String content, boolean result, int choose) {// 通过方法传入的choose来决定使用哪种算法if (choose == 0) {if (content.endsWith("0")) {result = true;}} else if (choose == 1) {if (content.startsWith("0")) {result = true;}}return result;}
策略模式
上面我们的例子是比较简单的,但是达到了演示的效果:校验授权的实现可能有多个版本,并且不同版本的实现都有可能被使用。为了后续方便扩展和维护,我们把checkInternal方法中的两个if判断中的逻辑再抽离出来。
首先定义一个策略接口:
public interface CheckStrategy {boolean check(String content);
}
然后将两个if中的逻辑转到接口的实现类中:
public class CheckStart implements CheckStrategy {@Overridepublic boolean check(String content) {boolean result = false;if (content.startsWith("0")) {result = true;}return result;}
}
public class CheckEnd implements CheckStrategy {@Overridepublic boolean check(String content) {boolean result = false;if (content.endsWith("0")) {result = true;}return result;}
}
接下来再调整一下LicenseService中方法的调用,把原来的checkInternal方法中的if语句进行调整,改为调用CheckStrategy中的方法:
public boolean checkLicense() {...result = checkInternal(content, new CheckStart());...
}private static boolean checkInternal(String content, CheckStrategy strategy) {return strategy.check(content);
}
更多思考
有说一种对于策略的说法是替换满屏的if else,我认为这不能算是策略模式的使用目的,只能算是应用了策略模式后的副产物。
它更多的使用场景是这样:有某一大方法,其中的一个环节可以有不同实现,并且进行环节的算法替换时不影响原大方法的功能(或受到预期的控制)。这里再举一些应用场景的例子,不够精准但重在体会其中的思想:
- 实现游戏可以用不同的底层引擎,引擎之间的替换可以应用策略模式
- 程序和数据库交互时可能用到不同的数据库产品如mysql、sqllite,对不同数据库的交互操作可以应用策略模式
- 别的我暂时想不起来了
Spring中实战
现在java web应用里Spring算是事实上的标准了,在Spring中用策略模式还是有一些小技巧的。下面直接给出代码请同学们品。
@Service
public class LicenseService {// 注入strategy manager@Autowiredprivate StrategyManager strategyManager;public boolean checkLicense() {boolean result = false;// abc0File file = Path.of("./secret").toFile();String content = "";try {// 读取文件内容BufferedReader br = new BufferedReader(new FileReader(file));content = br.readLine();br.close();} catch (Exception e) {e.printStackTrace();}// 由manager作为策略类实现的提供者result = strategyManager.pickCheckStrategy(CheckStrategyEnum.START.toString()).check(content);return result;}
}
@Service
public class StrategyManager {// 注入CheckStrategy list@Autowiredprivate List<CheckStrategy> checkStrategyList;public CheckStrategy pickCheckStrategy(String type) {// 根据传入的type从上面list中取出对应的策略实现类并返回给调用者return checkStrategyList.stream().filter(s -> s.type().equals(type)).findFirst().orElseThrow();}
}enum CheckStrategyEnum {END, START;
}
public interface CheckStrategy {/*** 返回策略实现类的类型,用于为manager提供实现类的标识** @return 自定义的枚举类型 {@link CheckStrategyEnum}*/String type();/*** 判断授权。算法由实现类确定** @param content 判断的内容* @return 是否判断成功*/boolean check(String content);
}
@Service
public class CheckStart implements CheckStrategy {@Overridepublic String type() {// 返回对应的枚举typereturn CheckStrategyEnum.END.toString();}@Overridepublic boolean check(String content) {boolean result = false;if (content.startsWith("0")) {result = true;}return result;}
}
@Service
public class CheckEnd implements CheckStrategy {@Overridepublic String type() {// 返回对应的枚举typereturn CheckStrategyEnum.START.toString();}@Overridepublic boolean check(String content) {boolean result = false;if (content.endsWith("0")) {result = true;}return result;}
}
相关文章:
Java设计模式——策略
前言 策略模式是平时Java开发中常用的一种,虽然已有很多讲解设计模式的文章,但是这里还是写篇文章来从自己理解的角度讲解一下。 使用场景 我们不妨进行场景假设,要对我们的软件进行授权管理:在启动我们的软件之前先要校验是否…...
线性代数的本质 1 向量
向量是线性代数中最为基础的概念。 何为向量? 从物理上看, 向量就是既有大小又有方向的量,只要这两者一定,就可以在空间中随便移动。 从计算机应用的角度看,向量和列表很接近,可以用来描述某对象的几个不同…...
基于JAVA的贫困地区人口信息管理系统 开源项目
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 人口信息管理模块2.2 精准扶贫管理模块2.3 特殊群体管理模块2.4 案件信息管理模块2.5 物资补助模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 人口表3.2.2 扶贫表3.2.3 特殊群体表3.2.4 案件表3.2.5 物资补助表 四…...
【后端高频面试题--Mybatis篇】
🚀 作者 :“码上有前” 🚀 文章简介 :后端高频面试题 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 后端高频面试题--Mybatis篇 什么是Mybatis?Mybatis的优缺点?Mybatis的特点…...
【笔记】Helm-5 Chart模板指南-12 .helmignore文件
.helmignore文件 .helmignore文件用来指定您不想包含在您的helm chart中的文件。 如果该文件存在,helm package命令会在打包应用时忽略所有在.helmignore文件中匹配的文件。 有助于避免不需要的或敏感文件及目录添加到您的helm chart中。 .helmignore文件支持Uni…...
【MySQL】表的增删改查(基础)
MySQL表的增删改查(基础) 1. CRUD2. 新增(Create)2.1 单行数据全列插入2.2 多行数据 指定列插入 3. 查询(Retrieve)3.1 全列查询3.2 指定列查询3.3 查询字段为表达式3.4 别名3.5 去重:DISTINCT…...
Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin
Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin 借鉴 Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心,Kotlin(2)-CSDN博客 在此基础上实现手指在屏幕上点击后&…...
C语言:表达式求值
引言:在笔试中,有一类的题目,题目给出代码,要求分析得出输出结果。这类题目更加考察我们对于运算顺序和运算类型转换的理解。文章介绍了隐式类型转换和操作符注意点,希望增加读者对于表达式求值的理解。 1.隐式类型转…...
GO 的 Web 开发系列(五)—— 使用 Swagger 生成一份好看的接口文档
经过前面的文章,已经完成了 Web 系统基础功能的搭建,也实现了 API 接口、HTML 模板渲染等功能。接下来要做的就是使用 Swagger 工具,为这些 Api 接口生成一份好看的接口文档。 一、写注释 注释是 Swagger 的灵魂,Swagger 是通过…...
【极数系列】Flink集成KafkaSink 实时输出数据(11)
文章目录 01 引言02 连接器依赖2.1 kafka连接器依赖2.2 base基础依赖 03 使用方法04 序列化器05 指标监控06 项目源码实战6.1 包结构6.2 pom.xml依赖6.3 配置文件6.4 创建sink作业 01 引言 KafkaSink 可将数据流写入一个或多个 Kafka topic 实战源码地址,一键下载可用…...
我为什么选择Xamarin开发ios app安卓app
临岁之寒简书作者,转载 Xamarin是一项跨平台开发技术,之前是收费的,而且据说收费不菲,所以使用的人数比较少,在国内几乎无人问津。后来Xamarin被微软收购,现已免费开放,相信今后国内的使用人群会大幅地增长…...
安全基础~通用漏洞4
文章目录 知识补充XSS跨站脚本**原理****攻击类型**XSS-后台植入Cookie&表单劫持XSS-Flash钓鱼配合MSF捆绑上线ctfshow XSS靶场练习 知识补充 SQL注入小迪讲解 文件上传小迪讲解 文件上传中间件解析 XSS跨站脚本 xss平台: https://xss.pt/ 原理 恶意攻击者…...
2024/2/12 图的基础知识 2
目录 查找文献 P5318 【深基18.例3】查找文献 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 有向图的拓扑序列 848. 有向图的拓扑序列 - AcWing题库 最大食物链计数 P4017 最大食物链计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 查找文献 P5318 【深基18.例3】…...
无人机飞行原理,多旋翼无人机飞行原理详解
多旋翼无人机升空飞行的首要条件是动力,有了动力才能驱动旋粪旋转,才能产生克服重力所必需的升力。使旋翼产生升力,进而推动多旋翼无人机升空飞行的一套设备装置称为动力装置,包括多旋翼无人机的发动机以及保证发动机正常工作所必…...
docker本地目录挂载
小命令 1、查看容器详情 docker inspect 容器名称 还是以nginx为例,上篇文章我们制作了nginx静态目录的数据卷,此时查看nginx容器时会展示出来(docker inspect nginx 展示信息太多,这里只截图数据卷挂载信息)&#…...
使用C++从零开始,自己写一个MiniWeb
第一步:新建项目 1、打开VS点击创建新项目 2、选择空项目并点下一步(切记不能选错项目类型) 3、填写项目名称和路径,点击创建即可 新建好后项目是这样的比较干净 4、右击源文件,点击添加,新建http.cpp文件…...
Android Graphics 图像显示系统 - 开篇
“ 随着学习的不断深入和工作经验的积累,欲将之前在博客中整理的Android Graphics知识做进一步整理,并纠正一些理解上的错误,故开设Graphics主题系列文章 ” 序言 由于工作需要,也源于个人兴趣,终于下决心花时间整理一…...
机器学习在各个行业的应用介绍
随着科技的飞速发展,机器学习已经从实验室走向了现实世界,逐渐成为各行各业不可或缺的工具。从金融领域到医疗健康,从零售市场到制造业,机器学习正在改变着我们的工作方式和生活质量。 本文将深入探讨机器学习在以下几个领域的应用…...
【生产实测有效】Windows命令行查看激活状态脚本
Windows查看激活状态关键代码 通过windows server 自带的PowerShell来执行 Get-WmiObject SoftwareLicensingProduct | Select-Object -Property Description, LicenseStatus | findstr "Operating System"|findstr "1$"Get-WmiObject SoftwareLicensingPr…...
简单的Udp服务器
目录 简单的UDP网络程序1.1 UdpServer.hpp1.2 UdpClient.cc1.3 main.cc1.4 makefile1.5 log.hpp 简单的UDP网络程序 1.1 UdpServer.hpp #pragma once#include <iostream> using namespace std;#include <unistd.h> #include <sys/types.h> #include <sy…...
Qwen3-32B内容创作应用:自动生成文案、报告、邮件
Qwen3-32B内容创作应用:自动生成文案、报告、邮件 1. 为什么选择Qwen3-32B进行内容创作 在当今内容为王的时代,企业每天都需要产出大量高质量的文字内容。从营销文案到产品说明,从客户邮件到内部报告,文字创作已经成为企业运营中…...
API密钥中转站,低成本实现Token自由
最近很多小伙伴都在用AI开发项目 编写程序,或者安装部署龙虾(OpenClaw),但是国内的模型很多又满足不了自己的要求,国外的模型要么是不方便购买,要么是价格太贵,每天都要消耗几十上百美元&#x…...
Realistic Vision V5.1 性能调优:针对STM32嵌入式设备图像生成的优化思路探讨
Realistic Vision V5.1 性能调优:针对STM32嵌入式设备图像生成的优化思路探讨 最近在捣鼓一个挺有意思的项目,想把一些前沿的AI图像生成能力,塞进像STM32F103C8T6这种资源极其有限的嵌入式设备里。你可能要问了,这怎么可能&#…...
嵌入式开发中PlantUML图表的工程化应用
嵌入式开发中PlantUML图表的工程化应用指南1. 嵌入式文档工具概述在嵌入式系统开发过程中,系统架构图和设计文档是工程师沟通需求、梳理逻辑的核心工具。传统拖拽式绘图工具存在效率低下、维护困难等问题,而基于代码生成图表的PlantUML技术为嵌入式开发文…...
深入解析C++菱形继承:虚基表的内存布局与优化策略
1. 菱形继承的本质问题 我第一次遇到菱形继承问题时,正在开发一个教育管理系统。当时需要设计Assistant类继承Student和Teacher,结果发现这两个父类都有从Person继承的_age成员。这导致每个Assistant对象里存了两份_age——这就是典型的数据冗余问题。 …...
NoFences终极指南:3步打造零杂乱的高效Windows桌面
NoFences终极指南:3步打造零杂乱的高效Windows桌面 【免费下载链接】NoFences 🚧 Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 还在为Windows桌面上的图标海洋而烦恼吗?NoFences作…...
华大单片机实战:MT25QL128/256 FLASH驱动避坑指南(HOLD引脚必看)
华大单片机深度实战:MT25QL系列FLASH驱动设计与HOLD引脚关键配置解析 在嵌入式存储解决方案中,NOR Flash因其高可靠性和快速随机读取特性,成为众多工业级应用的首选。MT25QL系列作为美光推出的高性能SPI NOR Flash产品,凭借其宽电…...
背单词花园:把单词种进长期记忆,告别背了就忘
为什么背单词花园抗遗忘效果出众?因为它把艾宾浩斯遗忘曲线,变成了看得见、好坚持的种花流程。一、新学单词 收获种子,记忆从第一步就扎根每次领取种子,就是开启一次新单词学习。用趣味场景完成初次编码,让单词不再是…...
mybatis实战进阶:基于快马生成缓存、分页与批量处理等生产级配置
mybatis实战进阶:基于快马生成缓存、分页与批量处理等生产级配置 最近在做一个用户管理系统时,遇到了不少mybatis的性能问题。单表查询还好,一旦涉及关联查询和批量操作,性能瓶颈就特别明显。经过一番摸索,总结出几个…...
Linux 0.11内核调试实战:手把手教你用Bochs+GDB定位第一次页故障(附完整答案)
Linux 0.11内核调试实战:从页故障到内存管理的深度探索 当你第一次在Linux 0.11内核实验中遇到页故障时,那种既兴奋又困惑的感觉可能还记忆犹新。作为操作系统学习者,理解页故障不仅是掌握内存管理的关键,更是通往内核深处的一扇门…...
