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

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开发中常用的一种&#xff0c;虽然已有很多讲解设计模式的文章&#xff0c;但是这里还是写篇文章来从自己理解的角度讲解一下。 使用场景 我们不妨进行场景假设&#xff0c;要对我们的软件进行授权管理&#xff1a;在启动我们的软件之前先要校验是否…...

线性代数的本质 1 向量

向量是线性代数中最为基础的概念。 何为向量&#xff1f; 从物理上看&#xff0c; 向量就是既有大小又有方向的量&#xff0c;只要这两者一定&#xff0c;就可以在空间中随便移动。 从计算机应用的角度看&#xff0c;向量和列表很接近&#xff0c;可以用来描述某对象的几个不同…...

基于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篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;后端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 后端高频面试题--Mybatis篇 什么是Mybatis&#xff1f;Mybatis的优缺点&#xff1f;Mybatis的特点…...

【笔记】Helm-5 Chart模板指南-12 .helmignore文件

.helmignore文件 .helmignore文件用来指定您不想包含在您的helm chart中的文件。 如果该文件存在&#xff0c;helm package命令会在打包应用时忽略所有在.helmignore文件中匹配的文件。 有助于避免不需要的或敏感文件及目录添加到您的helm chart中。 .helmignore文件支持Uni…...

【MySQL】表的增删改查(基础)

MySQL表的增删改查&#xff08;基础&#xff09; 1. CRUD2. 新增&#xff08;Create&#xff09;2.1 单行数据全列插入2.2 多行数据 指定列插入 3. 查询&#xff08;Retrieve&#xff09;3.1 全列查询3.2 指定列查询3.3 查询字段为表达式3.4 别名3.5 去重&#xff1a;DISTINCT…...

Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin

Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置&#xff0c;Kotlin 借鉴 Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心&#xff0c;Kotlin&#xff08;2&#xff09;-CSDN博客 在此基础上实现手指在屏幕上点击后&…...

C语言:表达式求值

引言&#xff1a;在笔试中&#xff0c;有一类的题目&#xff0c;题目给出代码&#xff0c;要求分析得出输出结果。这类题目更加考察我们对于运算顺序和运算类型转换的理解。文章介绍了隐式类型转换和操作符注意点&#xff0c;希望增加读者对于表达式求值的理解。 1.隐式类型转…...

GO 的 Web 开发系列(五)—— 使用 Swagger 生成一份好看的接口文档

经过前面的文章&#xff0c;已经完成了 Web 系统基础功能的搭建&#xff0c;也实现了 API 接口、HTML 模板渲染等功能。接下来要做的就是使用 Swagger 工具&#xff0c;为这些 Api 接口生成一份好看的接口文档。 一、写注释 注释是 Swagger 的灵魂&#xff0c;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 实战源码地址,一键下载可用&#xf…...

我为什么选择Xamarin开发ios app安卓app

临岁之寒简书作者,转载 Xamarin是一项跨平台开发技术&#xff0c;之前是收费的&#xff0c;而且据说收费不菲&#xff0c;所以使用的人数比较少&#xff0c;在国内几乎无人问津。后来Xamarin被微软收购&#xff0c;现已免费开放&#xff0c;相信今后国内的使用人群会大幅地增长…...

安全基础~通用漏洞4

文章目录 知识补充XSS跨站脚本**原理****攻击类型**XSS-后台植入Cookie&表单劫持XSS-Flash钓鱼配合MSF捆绑上线ctfshow XSS靶场练习 知识补充 SQL注入小迪讲解 文件上传小迪讲解 文件上传中间件解析 XSS跨站脚本 xss平台&#xff1a; https://xss.pt/ 原理 恶意攻击者…...

2024/2/12 图的基础知识 2

目录 查找文献 P5318 【深基18.例3】查找文献 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 有向图的拓扑序列 848. 有向图的拓扑序列 - AcWing题库 最大食物链计数 P4017 最大食物链计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 查找文献 P5318 【深基18.例3】…...

无人机飞行原理,多旋翼无人机飞行原理详解

多旋翼无人机升空飞行的首要条件是动力&#xff0c;有了动力才能驱动旋粪旋转&#xff0c;才能产生克服重力所必需的升力。使旋翼产生升力&#xff0c;进而推动多旋翼无人机升空飞行的一套设备装置称为动力装置&#xff0c;包括多旋翼无人机的发动机以及保证发动机正常工作所必…...

docker本地目录挂载

小命令 1、查看容器详情 docker inspect 容器名称 还是以nginx为例&#xff0c;上篇文章我们制作了nginx静态目录的数据卷&#xff0c;此时查看nginx容器时会展示出来&#xff08;docker inspect nginx 展示信息太多&#xff0c;这里只截图数据卷挂载信息&#xff09;&#…...

使用C++从零开始,自己写一个MiniWeb

第一步&#xff1a;新建项目 1、打开VS点击创建新项目 2、选择空项目并点下一步&#xff08;切记不能选错项目类型&#xff09; 3、填写项目名称和路径&#xff0c;点击创建即可 新建好后项目是这样的比较干净 4、右击源文件&#xff0c;点击添加&#xff0c;新建http.cpp文件…...

Android Graphics 图像显示系统 - 开篇

“ 随着学习的不断深入和工作经验的积累&#xff0c;欲将之前在博客中整理的Android Graphics知识做进一步整理&#xff0c;并纠正一些理解上的错误&#xff0c;故开设Graphics主题系列文章 ” 序言 由于工作需要&#xff0c;也源于个人兴趣&#xff0c;终于下决心花时间整理一…...

机器学习在各个行业的应用介绍

随着科技的飞速发展&#xff0c;机器学习已经从实验室走向了现实世界&#xff0c;逐渐成为各行各业不可或缺的工具。从金融领域到医疗健康&#xff0c;从零售市场到制造业&#xff0c;机器学习正在改变着我们的工作方式和生活质量。 本文将深入探讨机器学习在以下几个领域的应用…...

【生产实测有效】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…...

手把手教你给51单片机项目“瘦身”:多传感器数据采集与显示的优化技巧

51单片机多传感器系统优化实战&#xff1a;从臃肿代码到高效工程的蜕变之路 当你的51单片机项目开始集成第三个、第四个传感器时&#xff0c;是否发现代码变得越来越难以维护&#xff1f;LCD显示刷新变得卡顿&#xff0c;传感器数据互相干扰&#xff0c;甚至整个系统会莫名其妙…...

基于Python的可穿戴设备的人机交互设计与实现

前言随着科技的进步发展&#xff0c;人们对生活水平提高有了一定的要求&#xff0c;穿戴设备得到了一定的普及与发展&#xff0c;人与设备之间交互的快捷性和智能化成为了提高用户体验感的关键所在。 对穿戴设备与人之间的交互的需求进行调查&#xff0c;分析用户在使用过程中存…...

vscode-remote-ssh-server首次安装或者更新无响应时解决方案

当vscode更新后&#xff0c;remote-ssh服务端的server也需要同步更新&#xff0c;否则会无法连接&#xff0c;若服务器的网络下载服务端文件非常慢或者无法连接外网&#xff0c;则需要手动下载离线包拷贝到对应的目录下。1、使用mobaXtern&#xff08;或者其他SSH工具&#xff…...

从“认怂”到“被看见”:flomo的产品设计哲学

当大多数笔记软件都在追求“大而全”时&#xff0c;有一款产品选择了一条完全不同的路。它不让你写标题&#xff0c;不支持复杂排版&#xff0c;甚至在官网上大大方方地列出“自己不擅长什么”。它的创始人说&#xff1a;“35岁再创业&#xff0c;我学会了认怂。”它就是flomo&…...

ClickHouse连接避坑指南:Python开发者常遇到的5个问题及解决方案

ClickHouse连接避坑指南&#xff1a;Python开发者常遇到的5个问题及解决方案 当Python开发者初次尝试与ClickHouse建立连接时&#xff0c;往往会遇到各种意料之外的障碍。这些看似简单的连接问题&#xff0c;实际上可能隐藏着深层次的配置陷阱或性能瓶颈。本文将深入剖析五个最…...

别再只用#if DEBUG了!C#预处理器指令的5个实战妙用(含#warning、#pragma避坑)

别再只用#if DEBUG了&#xff01;C#预处理器指令的5个实战妙用&#xff08;含#warning、#pragma避坑&#xff09; 在C#开发中&#xff0c;预处理器指令往往被简化为#if DEBUG的单一用途&#xff0c;这就像只把瑞士军刀当作开瓶器使用。实际上&#xff0c;这套工具能在代码质量管…...

开源工具技术解析与实践指南:突破游戏性能限制的完整方案

开源工具技术解析与实践指南&#xff1a;突破游戏性能限制的完整方案 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 一、问题溯源&#xff1a;帧率限制背后的技术债务分析 当高端显卡在…...

[ linux添加应用图标到桌面 ] : 中将应用程序添加图标(快捷方式 ),并放置任务栏中,.desktop文件使用

.desktop文件格式在你的主目录中打开终端(ctrlaltt)&#xff0c;接着输入以下代码&#xff1a;touch test.desktop vim test.desktop这里我选择的是vim的编辑方式&#xff0c;当然如果你没有vim或者说不太熟练的话&#xff0c;你可以直接双击打开该文件。代码解释&#xff1a;t…...

别再折腾官方源了!用XianDian-IaaS-v2.2在CentOS7上30分钟搞定OpenStack最小化部署

30分钟极速部署OpenStack&#xff1a;XianDian-IaaS在CentOS7上的实战指南 OpenStack作为开源云计算平台的标杆&#xff0c;其强大的灵活性和模块化设计吸引了大量企业用户。但官方部署流程的复杂性往往让初学者望而却步——依赖项冲突、版本兼容性问题、繁琐的配置步骤&#x…...

长期用嘴呼吸,颈肩肌肉代偿性紧张

很多人因为鼻塞、习惯等原因长期用嘴呼吸&#xff0c;却不知道这会导致颈肩肌肉代偿性紧张&#xff0c;影响颈腰椎健康。用嘴呼吸时&#xff0c;头部会不自觉地向前伸、仰起&#xff0c;颈椎长期处于过度前屈或后伸状态&#xff0c;颈部肌肉持续牵拉&#xff0c;容易导致肌肉劳…...