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

【设计模式】策略模式在Java工程中应用

在之前的文章中,曾经给大家介绍过策略模式:【设计模式】策略模式,在该篇文章中,我们曾很清楚的说到,策略模式主要解决的问题是:在有多种算法相似的情况下,解决使用 if...else 所带来的复杂和难以维护。策略模式使我们的实现更加符合开闭原则:面向扩展开发,面向修改关闭。在后来的学习和工作的多次应用中,有了更加深刻的认识。再次总结此篇文章赘述下。

此篇文章,将以创建订单为例,创建不同类型的订单,不同类型的订单不同的处理逻辑。

类图:

代码:

  1. 抽象策略(Strategy)角色:抽象策略角色由抽象类或接口来承担,它给出具体策略角色需要实现的接口;

package strategyTest;import strategyTest.dto.BaseRequestDTO;/*** 类 名 称:CreateStrategy* 类 描 述:策略抽象类* 创建时间:2023/2/20 3:46 下午* 创 建 人:admin*/
public abstract class AbstractOrderStrategy {public abstract Boolean isPracticable(BaseRequestDTO dto);// 业务执行总流程public ResponseResult process(BaseRequestDTO dto) {ResponseResult paramsValidate = validateParams(dto);if (!paramsValidate.isSuccess()) {return paramsValidate;}ResponseResult ruleValidate = validateRules(dto);if (!ruleValidate.isSuccess()) {return ruleValidate;}ResponseResult processResult = doProcess(dto);if(processResult.isSuccess()){postProcessAction(dto);}return processResult;}// 参数校验protected abstract ResponseResult validateParams(BaseRequestDTO dto);// 业务规则校验protected abstract ResponseResult validateRules(BaseRequestDTO dto);// 核心实现protected abstract ResponseResult doProcess(BaseRequestDTO dto);// 后置处理(异步操作等)protected abstract void postProcessAction(BaseRequestDTO dto);
}

2.具体策略(ConcreteStrategy)角色:实现封装了具体的算法或行为;

顺风车类型处理:

package strategyTest.impl;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import strategyTest.AbstractOrderStrategy;
import strategyTest.ResponseResult;
import strategyTest.dto.BaseRequestDTO;
import strategyTest.dto.SfcRequestDTO;/*** 类 名 称:SfcImpl* 类 描 述:TODO* 创建时间:2023/2/20 3:58 下午* 创 建 人:admin*/
@Service
public class SfcImpl extends AbstractOrderStrategy {private Logger logger = LoggerFactory.getLogger(SfcImpl.class);@Overridepublic Boolean isPracticable(BaseRequestDTO dto) {if(dto.getType() == 1){return true;}return false;}@Overrideprotected ResponseResult validateParams(BaseRequestDTO dto) {SfcRequestDTO sfcRequestDTO = (SfcRequestDTO) dto;if (sfcRequestDTO.getIsShare() == null || sfcRequestDTO.getIsShare() == 0) return ResponseResult.ERROR;logger.info("sfc validateParams success");return ResponseResult.SUCCESS;}@Overrideprotected ResponseResult validateRules(BaseRequestDTO dto) {// 无校验return ResponseResult.SUCCESS;}@Overrideprotected ResponseResult doProcess(BaseRequestDTO dto) {logger.info("sfc doProcess success");return ResponseResult.SUCCESS;}@Overrideprotected void postProcessAction(BaseRequestDTO dto) {logger.info("sfc 异步执行...");}}

巴士订单处理:

package strategyTest.impl;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import strategyTest.AbstractOrderStrategy;
import strategyTest.ResponseResult;
import strategyTest.dto.BaseRequestDTO;
import strategyTest.dto.BusRequestDTO;/*** 类 名 称:BusImpl* 类 描 述:TODO* 创建时间:2023/2/20 3:58 下午* 创 建 人:admin*/
@Service
public class BusImpl extends AbstractOrderStrategy {private Logger logger = LoggerFactory.getLogger(BusImpl.class);@Overridepublic Boolean isPracticable(BaseRequestDTO dto) {if (dto.getType() == 2) {return true;}return false;}@Overrideprotected ResponseResult validateParams(BaseRequestDTO dto) {BusRequestDTO busRequestDTO = (BusRequestDTO) dto;if (busRequestDTO.getRouteId() == null || busRequestDTO.getRouteId() == 0) return ResponseResult.ERROR;logger.info("bus validateParams success");return ResponseResult.SUCCESS;}@Overrideprotected ResponseResult validateRules(BaseRequestDTO dto) {BusRequestDTO busRequestDTO = (BusRequestDTO) dto;if (busRequestDTO.getSeats() != null && busRequestDTO.getSeats() > 30) return ResponseResult.ERROR;logger.info("bus validateRules success");return ResponseResult.SUCCESS;}@Overrideprotected ResponseResult doProcess(BaseRequestDTO dto) {logger.info("bus doProcess success");return ResponseResult.SUCCESS;}@Overrideprotected void postProcessAction(BaseRequestDTO dto) {logger.info("bus 异步执行...");}}

3.上下文(Context)角色:持有抽象策略类的引用。(引用,执行策略)

package strategyTest;import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import strategyTest.dto.BaseRequestDTO;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** 类 名 称:StrategyContext* 类 描 述:策略执行上下文* 创建时间:2023/2/20 3:47 下午* 创 建 人:admin*/
@Component
public class StrategyContext{// 策略管理类@Autowiredprivate List<AbstractOrderStrategy> strategies = new ArrayList<>();// 获取策略类public AbstractOrderStrategy getStrategy(BaseRequestDTO dto) {for (AbstractOrderStrategy strategy : strategies) {if (strategy.isPracticable(dto)) {return strategy;}}return null;}}

调用方client:

可以在一个controller,也可以写在多个controller

package strategyTest.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import strategyTest.AbstractOrderStrategy;
import strategyTest.ResponseResult;
import strategyTest.StrategyContext;
import strategyTest.dto.BaseRequestDTO;
import strategyTest.dto.BusRequestDTO;
import strategyTest.dto.SfcRequestDTO;/*** 类 名 称:客户端请:可以充当controller或者业务调用上游* 类 描 述:TODO* 创建时间:2023/2/20 3:58 下午* 创 建 人:admin*/
@RestController
public class ClientTest {@Autowiredprivate StrategyContext strategyContext;@RequestMapping("/createSfc")public ResponseResult createSfc(SfcRequestDTO sfcRequestDTO){if(sfcRequestDTO == null){return ResponseResult.ERROR;}return this.createOrder(sfcRequestDTO);}@RequestMapping("/createBus")public ResponseResult createBus(BusRequestDTO busRequestDTO){if(busRequestDTO == null){return ResponseResult.ERROR;}return this.createOrder(busRequestDTO);}private ResponseResult createOrder(BaseRequestDTO baseRequestDTO) {AbstractOrderStrategy strategy = strategyContext.getStrategy(baseRequestDTO);if(strategy == null){return ResponseResult.ERROR;}return strategy.process(baseRequestDTO);}
}

我们看下运行结果:

sfc运行结果:

bus运行结果:

是不是非常简洁明了!!!

我们看完代码,再结合类图看下,此时如果我们想新增一种类型的创建订单流程,比如创建一笔代驾订单,需要如何做? 我们只需要做两步:

1、新增一个代驾的实现类DjImpl,继承StrategyContext类;

2、在Controller中,新增一个方法(如果不同类型的订单有不在同一个controller,可将createOrder方法抽象到父类controller,此时新增一个子类controller继承父类和父类的方法即可);

其他地方无需改动。。。其他类型的创建订单流程完全无改动,无影响。下单流程解耦,测试范围极大的降低。

想想我们在项目中,相似的场景写过多少if else。每次添加新的实现,是否影响到原有功能。结合这篇文章,希望能对读者朋友有所帮助。

总结:

策略模式帮助我们把相似的算法抽象,使用上下文管理抽象类的具体实现,每次新增算法时,只需新增具体实现。使我们的代码轻松解耦,符合开闭原则,极大的缩小了影响范围。是成为一名优秀工程师的必修课!

相关文章:

【设计模式】策略模式在Java工程中应用

在之前的文章中&#xff0c;曾经给大家介绍过策略模式&#xff1a;【设计模式】策略模式&#xff0c;在该篇文章中&#xff0c;我们曾很清楚的说到&#xff0c;策略模式主要解决的问题是&#xff1a;在有多种算法相似的情况下&#xff0c;解决使用 if...else 所带来的复杂和难以…...

Linux驱动开发工程师需要掌握哪些技能?

一、前言 Linux驱动开发是一项高度技术性的工作&#xff0c;需要深厚的编程技能和对计算机硬件的深入理解。随着物联网、人工智能等领域的快速发展&#xff0c;Linux驱动开发工程师的需求日益增加。在这篇文章中&#xff0c;我将为您介绍一条Linux驱动开发工程师的学习路线&am…...

【人脸识别】FROM:提升遮挡状态下的人脸识别效果

论文题目&#xff1a;《End2End Occluded Face Recognition by Masking Corrupted Features》 论文地址&#xff1a;https://arxiv.org/pdf/2108.09468v3.pdf 代码地址&#xff1a;https://github.com/haibo-qiu/from 1.前言 人脸识别技术已经取得了显著的进展&#xff0c;主要…...

浏览器缓存

什么是缓存? 当第一次访问网站的时候,比如www.baidu.com,电脑会图片,文件等下载下来,当第二次访问网站的时候,网站就会直接被加载出来. 缓存的好处? 减轻服务器压力,减少请求的放松.提高性能,在本地打开资源肯定比在服务器上获取要快减少宽带的消耗,当我们使用缓存时,只会…...

【软考 系统架构设计师】论文范文③ 论数据访问层设计技术及其应用

>>回到总目录<< 文章目录 论数据访问层设计技术及其应用范文摘要正文论数据访问层设计技术及其应用 在信息系统的开发与建设中,分层设计是一种常见的架构设计方法,区分层次的目的是为了实现“高内聚低耦合”的思想。分层设计能有效简化系统复杂性,使设计结构清…...

802.11 MCS 的最低SNR分析

常常看到这样的表格: 那么这个SNR如何而来? 看看RSSI和SNR的关系,它们之间隔了一个noise floor。从表格看得出,这个底噪在-80~-90之间。 而SNR的核心,也有类似的原因,它和BER有关。...

用于C++的对象关系映射库—YB.ORM

1 介绍YB.ORM YB.ORM 旨在简化与关系数据库交互的 C 应用程序的开发。 对象关系映射器(ORM) 通过将数据库表映射到类并将表行映射到应用程序中的对象来工作&#xff0c;这种方法可能不是对每个数据库应用程序都是最佳的&#xff0c;但它被证明在需要复杂逻辑和事务处理的应用程…...

Cesium 100K数据加载 支持弹窗 动态更改位置

前言&#xff1a;今天总结关于point、label、billboard海量数据加载。后续会研究下大量model加载以及大bim(几百G上T)模型记载 海量点加载 弹窗 加载点位时&#xff0c;不加载弹窗。点击点位时在加载弹窗&#xff0c;及有效的减少加载量&#xff0c;优化性能。 const handler …...

MySQL管理表

在创建表时需要提前了解mysql里面的数据类型 常见的数据类型 创建表 创建表方式1&#xff1a; 格式&#xff1a; CREATE TABLE [IF NOT EXISTS] 表名( 字段1, 数据类型 [约束条件] [默认值], 字段2, 数据类型 [约束条件] [默认值], 字段3, 数据类型 [约束条件] [默认值], ………...

【Java 面试合集】打印一个int整数的32位表示

打印一个int整数的32位表示 1. 概述 嗨&#xff0c;大家好【Java 面试合集】又来了&#xff0c;今天给大家分享的主题是打印一个int整数的32位表示. 2. 32位分析 2.1 为什么是32位呢 不知道看到这篇文章的各位是否都知道&#xff0c;一个int类型的表示方式就是32位呢&#x…...

这样在管理后台里实现 403 页面实在是太优雅了

前言403 页面通常表示无权限访问&#xff0c;与 404 页面代表着不同含义。而大部分管理后台框架仅提供了 404 页面的支持&#xff0c;但却忽略了对 403 页面的处理&#xff0c;有的框架虽然也有对 403 页面的处理&#xff0c;但处理效果却不尽人意。那怎么样的 403 页面才是即好…...

c++提高篇——STL常用算法

STL常用算法一、常用遍历算法一、for_each 遍历容器二、transform 搬运容器到另一个容器中二、常用查找算法一、find二、find_if三、adjacent_find四、binary_search五、count六、count_if三、常用排序算法一、sort二、random_shuffle三、 merage四、reverse四、常用拷贝和替换…...

Materials - DistanceField Nodes

以前的相关笔记&#xff0c;归档发布&#xff1b;距离场相关节点&#xff1a;DistanceToNearestSurface节点&#xff1a;求出传入的Position位置到最近的面的距离并输出&#xff0c;在没有Position输入的时候&#xff0c;默认值会直接使用World Position&#xff1a;Position的…...

【ARMv8 编程】ARMv8 指令集介绍

ARMv8 架构中引入的最重要的变化之一是增加了 64 位指令集。该指令集补充了现有的 32 位指令集架构。这种增加提供了对 64 位宽整数寄存器和数据操作的访问&#xff0c;以及使用 64 位长度的内存指针的能力。新指令被称为 A64&#xff0c;以 AArch64 执行状态执行。ARMv8 还包括…...

大数据之Phoenix基本介绍

文章目录前言一、Phoenix简介二、Phoenix入门&#xff08;一&#xff09;创建表语法&#xff08;二&#xff09;查看表信息&#xff08;三&#xff09;删除表&#xff08;四&#xff09;大小写问题前言 #博学谷IT学习技术支持# 上篇文章介绍了Phoenix环境搭建&#xff0c;点击…...

算法leetcode|38. 外观数列(多语言实现)

文章目录38. 外观数列&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a;分析&#xff1a;题解&#xff1a;rustgocpythonjava38. 外观数列&#xff1a; 给定一个正整数 n &#xff0c;输出外观数列的第 n 项。 「外观数列」是一个整数序列&#xff0c;从数字…...

异步交互的关键——Ajax

文章目录1,Ajax 概述1.1 作用1.2 同步和异步1.3 案例1.3.1 分析1.3.2 后端实现1.3.3 前端实现2&#xff0c;axios2.1 基本使用2.2 快速入门2.2.1 后端实现2.2.2 前端实现2.3 请求方法别名最后说一句1,Ajax 概述 AJAX (Asynchronous JavaScript And XML)&#xff1a;异步的 Jav…...

Android自定义View实现打钩签到动画

效果图实现原理我们看实现的动画效果&#xff0c;其实是分为1. 绘制未选中状态图形&#xff08;圆弧和对号&#xff09;2. 绘制选中状态圆弧的旋转的动画3. 绘制选中状态圆弧向中心收缩铺满动画4. 绘制选中状态对号5. 绘制选中状态下圆的放大回弹动画6. 暴露接口接口回调传递选…...

python+pytest接口自动化(3)-接口测试一般流程及方法

首先我们要明确&#xff0c;通常所接口测试其实就属于功能测试&#xff0c;主要校验接口是否实现预定的功能&#xff0c;虽然有些情况下可能还需要对接口进行性能测试、安全性测试。在学习接口自动化测试之前&#xff0c;我们先来了解手工接口测试怎样进行。URL组成为了更好的理…...

《MySQL学习》 表中随机取记录的方式

一.初始化测试表 创建表 words CREATE TABLE words ( id int(11) NOT NULL AUTO_INCREMENT, word varchar(64) DEFAULT NULL, PRIMARY KEY (id)) ENGINEInnoDB;插入测试数据 create procedure idata()begin declare i int; set i 0; while i<10000 do insert into words…...

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

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

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...

Linux基础开发工具——vim工具

文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...

Android屏幕刷新率与FPS(Frames Per Second) 120hz

Android屏幕刷新率与FPS(Frames Per Second) 120hz 屏幕刷新率是屏幕每秒钟刷新显示内容的次数&#xff0c;单位是赫兹&#xff08;Hz&#xff09;。 60Hz 屏幕&#xff1a;每秒刷新 60 次&#xff0c;每次刷新间隔约 16.67ms 90Hz 屏幕&#xff1a;每秒刷新 90 次&#xff0c;…...