解锁Spring Boot中的设计模式—03.委派模式:探索【委派模式】的奥秘与应用实践!

委派模式

文章目录

  • 委派模式
    • 1.简述
      • **应用场景**
      • **优缺点**
      • **业务场景示例**
    • 2.类图
    • 3.具体实现
      • 3.1.自定义注解
      • 3.2.定义抽象委派接口
      • 3.3.定义具体执行者
      • 3.4.定义委派者(统一管理委派任务)
      • 3.5.定义委派者管理类
    • 4.测试
      • 4.1.controller层
      • 4.2.测试不同场景
        • 4.2.1.测试生产部门计算费用
        • 4.2.2.测试财务部门计算费用
        • 4.2.3.测试各种类型传值

1.简述

委派模式是一种负责任务的调度和分配模式,类似于代理模式但更注重结果而非过程。它可以被视为一种特殊情况下的静态代理的全权代理,但并不属于GOF 23种设计模式之一,而是归类为行为型模式。

委派模式在Spring框架中广泛应用,其中最常见的例子是DispatcherServlet,它充分利用了委派模式的特性。

在Spring框架中,DispatcherServlet是一个核心组件,负责接收HTTP请求并将其分发给相应的处理器(Controller)进行处理。DispatcherServlet利用了委派模式的特性来实现请求的转发和处理。

具体来说,DispatcherServlet接收到HTTP请求后,根据请求的信息(如URL、请求方法等),会将请求委派给相应的处理器进行处理。这个委派的过程就是典型的委派模式应用。

在Spring中,DispatcherServlet并不直接处理请求,而是通过HandlerMapping确定请求对应的处理器(Controller),然后委派给对应的Controller进行处理。处理完成后,再由DispatcherServlet负责返回响应给客户端。

这种设计使得Spring的Web应用具有良好的灵活性和可扩展性。开发者可以根据自己的需求定制不同的HandlerMapping和Controller,而DispatcherServlet作为统一的入口,负责请求的委派和响应的处理,使得整个Web应用的架构更加清晰和易于维护。

应用场景

委派模式适用于以下场景:

  • 当需要实现表现层与业务层之间的松耦合时,委派模式能够提供一个良好的解决方案。
  • 在需要编排多个服务之间的调用时,特别是像责任链模式这样的情况下,委派模式尤为适用。
  • 当需要再封装一层服务查找和调用时,委派模式也是一种常见的选择。

优缺点

优点

  • 隐藏实现:对内部实现进行了封装,使得调用方不必关心具体的实现细节,增强了系统的安全性和稳定性。
  • 易于扩展:通过委派模式,可以方便地添加新的服务或功能,而不会影响到已有的代码。
  • 简化调用:调用方只需要知道委派对象,而不需要知道具体的执行细节,降低了系统的复杂度和维护成本。

缺点

  • 膨胀和管理难度:与静态代理相似,随着具体执行类和委派类的扩展,代码容易膨胀,难以管理,需要谨慎设计和维护。

业务场景示例

在关务系统中,费用计算是一个关键功能。不同部门可能采用不同的计算方式。为了应对这种多样性,系统需要根据不同部门的要求,动态选择合适的费用计算算法,以确保费用的准确性和合规性。

在这样的场景下,可以借助委派模式来实现动态选择合适的计算算法。下面,我们以Spring Boot版本的委派模式为例来展示其具体实现。

2.类图

在这里插入图片描述

3.具体实现

3.1.自定义注解

import java.lang.annotation.*;@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Delegate {/*** 执行任务类型*/String type () default "";
}

3.2.定义抽象委派接口

/*** 委派任务通用处理接口*/
public interface DelegateHandler<R,T> {/*** 抽象处理方法* @param t 处理任务参数*/R process(T t);
}

3.3.定义具体执行者

/*** 财务部门委派类* @author 13723* @version 1.0* 2024/1/7 14:52*/
@Delegate(type = "finance")
@Component
public class FinanceDepartmentDelegate implements DelegateHandler<ResultObject, BigDecimal>{private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 财务部门处理(将数据加上税费)* @param s 处理任务参数* @return*/@Overridepublic ResultObject process(BigDecimal s) {ResultObject instance = ResultObject.createInstance(true);BigDecimal res = BigDecimal.ZERO;if (s != null) {res = s.add(new BigDecimal("300"));instance.setData(res);}instance.setMessage("财务部门处理数据结束!");logger.error("财务部门处理数据结束!处理前:{},处理后:{}",s,res);return instance;}
}/*** 生产部门委派类* @author 13723* @version 1.0* 2024/1/7 14:44*/
@Delegate(type = "product")
@Component
public class ProductionDepartmentDelegate implements DelegateHandler<ResultObject, BigDecimal> {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 生产部门处理(将数据重新计算)* @param s 处理任务参数* @return*/@Overridepublic ResultObject process(BigDecimal s) {ResultObject instance = ResultObject.createInstance(true);BigDecimal res = BigDecimal.ZERO;if (s != null) {res = s.multiply(new BigDecimal("1.6"));instance.setData(res);}instance.setMessage("生产部门处理数据结束!");logger.error("生产部门处理数据结束!处理前:{},处理后:{}",s,res);return instance;}
}

3.4.定义委派者(统一管理委派任务)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.CollectionUtils;import java.lang.invoke.MethodHandles;
import java.util.*;/***  委派角色管理类* @author 13723* @version 1.0* 2024/1/7 14:58*/
@Delegate
public class DelegateManager extends DelegatePatternConfiguration {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 存放具体委派角色类型* k-具体委派类型* v-具体任务角色*/private Map<String, List<DelegateHandler>> handlerMap;/*** 存放委派模式中的各种真正执行任务的角色* 分组放* @param iHandlerList*/public void setHandlerMap(List<DelegateHandler> iHandlerList) {handlerMap = scanHandlers(iHandlerList);}/*** 将具体的委派角色 获取进行统一管理* @param handlerList 具体实现委派的类集合* @return 存放委派*/private Map<String, List<DelegateHandler>> scanHandlers(List<DelegateHandler> handlerList) {ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);scanner.addIncludeFilter(new AnnotationTypeFilter(Delegate.class));Map<String, List<DelegateHandler>> handlerMap = new HashMap<>();for (DelegateHandler handler : handlerList) {Class<?> targetClass = handler.getClass();if (hasDutyAnnotation(targetClass)) {String type = getTypeAnnotationValue(targetClass);handlerMap.computeIfAbsent(type, key -> new ArrayList<>()).add(handler);}}return handlerMap;}/*** 判断该类是否是 使用使用了Delegate注解* @param clazz 类名称* @return true使用了*/private boolean hasDutyAnnotation(Class<?> clazz ) {return AnnotationUtils.findAnnotation(clazz, Delegate.class) != null;}/*** 判断使用了的注解@Delegate 是否填写了类型* @param clazz* @return*/private String getTypeAnnotationValue(Class<?> clazz) {Delegate dutyAnnotation = AnnotationUtils.findAnnotation(clazz, Delegate.class);if (dutyAnnotation == null) {throw new IllegalStateException("Delegate annotation not found for class: " + clazz);}return dutyAnnotation.type();}/*** 根据类型 委派具体执行任务的角色* @param type 任务类型* @param t 传递参数* @return 执行后 最终返回结果*/public <R, T> R process(String type, T t) {List<DelegateHandler> handlers = handlerMap.get(type);R result = null;if (!CollectionUtils.isEmpty(handlers)) {// 注意 这里需要考虑多个执行角色问题,遇到多个相同类型执行角色,考虑使用责任链,别再此模式上死磕。for (DelegateHandler<R, T> handler : handlers) {result = handler.process(t);}}else {throw new RuntimeException("no match delegate class !");}return result;}
}

3.5.定义委派者管理类

/*** 将 委派模式管理类 注入到Spring中* @author 13723* @version 1.0* 2024/1/7 15:16*/
@Configuration
public class DelegatePatternConfiguration {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Beanpublic DelegateManager delegateManager(List<DelegateHandler> handlers) {// 创建对象 会获取全部使用注解的类,将其注入到对应map集合中DelegateManager delegateManager = new DelegateManager();delegateManager.setHandlerMap(handlers);return delegateManager;}
}

4.测试

4.1.controller层

import com.hrfan.java_se_base.config.ResultObject;
import com.hrfan.java_se_base.pattern.decorator_pattern.config.DecorateManager;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.util.Objects;/*** 委派模式测试类* @author 13723* @version 1.0* 2024/1/7 15:20*/
@RestController
@RequestMapping("/v1/delegate")
public class DelegateTestController {@Resourceprivate DelegateService service;private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@ResourceDelegateManager manager;@PostMapping("/test")public ResultObject test(@RequestBody DelegateMoneyParams params){ResultObject instance = ResultObject.createInstance(false);instance.setMessage("计算失败!");Objects.requireNonNull(params);if (StringUtils.isNotBlank(params.getType())){switch (params.getType()){case "a":instance =  manager.process("product", params.getTotal());return instance;case "b":instance =  manager.process("finance", params.getTotal());return instance;default:return instance;}}return instance;}
}

4.2.测试不同场景

4.2.1.测试生产部门计算费用

在这里插入图片描述

4.2.2.测试财务部门计算费用

在这里插入图片描述

4.2.3.测试各种类型传值

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/687486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GPT-2】论文解读:Language Models are Unsupervised Multitask Learners

文章目录 介绍zero-shot learning 零样本学习 方法数据Input Representation 结果 论文&#xff1a;Language Models are Unsupervised Multitask Learners 作者&#xff1a;Alec Radford, Jeff Wu, Rewon Child, D. Luan, Dario Amodei, I. Sutskever 时间&#xff1a;2019 介…

C++中.h与.hpp文件的差异问答

.h文件与.hpp文件在C编程中的区别主要基于约定和偏好&#xff0c;而不是C语言或其编译器强制执行的任何技术差异。以下是这些差异的概述&#xff1a; 约定&#xff1a; .h 文件&#xff1a;此扩展名源于C编程&#xff0c;表示头文件。它在C中常用于头文件&#xff0c;但不一定表…

四种mfc140u.dll丢失的解决方法,有效恢复mfc140u.dll丢失

mfc140u.dll文件的重要性&#xff0c;当系统中出现mfc140u.dll丢失的情况时&#xff0c;可能会导致一系列问题和影响。因此&#xff0c;保持mfc140u.dll文件的完整性对于系统和应用程序的稳定运行至关重要。一旦出现mfc140u.dll文件丢失的情况&#xff0c;我们需要采取有效的方…

怎样录屏?掌握这些方法,让你轻松驾驭!

随着科技的进步&#xff0c;如今我们可以通过屏幕录制软件来记录我们的电脑屏幕活动。无论是为了分享游戏精彩瞬间&#xff0c;还是为了制作教程或演示&#xff0c;录屏都成为了许多人的需求。可是你知道怎样录屏才是最好的吗&#xff1f;接下来&#xff0c;本文将为您介绍三种…

前端面试必备八股文——HTMLCSS

HTML src和href的区别 src和href都是用来加载外部资源&#xff0c;区别如下 src当浏览器解析到该元素时&#xff0c;会暂停其他资源的加载和处理&#xff0c;直到该资源加载完成。 它会将资源内容嵌入到当前标签所在的位置&#xff0c;将其指向的资源下载应用到文档内&#…

Mybatis速成(一)

文章目录 Mybatis速成&#xff08;一&#xff09;前言1. 快速入门1.1 入门程序分析1.2 入门程序实现1.2.1 准备工作1.2.1.1 创建springboot工程1.2.1.2 数据准备 1.2.2 配置Mybatis1.2.3 编写SQL语句1.2.4 单元测试 1.3 解决SQL警告与提示 2. JDBC介绍(了解)2.1 介绍2.2 代码2.…

本地个性化聊天机器人CHAT WITH RTX

英伟达推出了自家版本的ChatGPT Chat With RTX 是一款演示应用程序&#xff0c;可让您个性化连接到您自己的内容&#xff08;文档、笔记、视频或其他数据&#xff09;的 GPT 大语言模型 (LLM)。利用检索增强生成 (RAG)、TensorRT-LLM和 RTX 加速&#xff0c;您可以查询自定义聊…

django定时任务(django-crontab)

目录 一&#xff1a;安装django-crontab&#xff1a; 二&#xff1a;添加django_crontab到你的INSTALLED_APPS设置&#xff1a; 三&#xff1a;运行crontab命令来创建或更新cron作业&#xff1a; 四&#xff1a;定义你的cron作业 五&#xff1a;创建你的管理命令&#xff…

《学成在线》微服务实战项目实操笔记系列(P92~P120)【下】

史上最详细《学成在线》项目实操笔记系列【下】&#xff0c;跟视频的每一P对应&#xff0c;全系列18万字&#xff0c;涵盖详细步骤与问题的解决方案。如果你操作到某一步卡壳&#xff0c;参考这篇&#xff0c;相信会带给你极大启发。 四、课程发布模块 4.1 (课程发布)模块需求…

【leetcode】深搜、暴搜、回溯、剪枝(C++)3

深搜、暴搜、回溯、剪枝&#xff08;C&#xff09;3 一、解数独1、题目描述2、代码3、解析 二、单词搜索1、题目描述2、代码3、解析 三、黄金矿工1、题目描述2、代码3、解析 四、不同路径III1、题目描述2、代码3、解析 一、解数独 1、题目描述 leetcode链接 2、代码 class…

三组I/O复用函数的比较

目录 事件集最大支持文件描述符数工作模式实现原理一图 这三组I/O复用系统调用&#xff0c;这三组系统调用都能同时监听多个文件描述符&#xff0c;它们将等待由timeout参数指定超时时间&#xff0c;知道一个或者多个文件描述上面有事件发生时候返回&#xff0c;返回的就是就绪…

AIGC ChatGPT4 教你如何完成业务需求SQL的编写

源表字段与数据信息为&#xff1a; 需求&#xff1a;现需要统计各部门各岗位下的平均工资 &#xff0c;将员工工资大于本岗位下平均工资的员工信息显示出来。 如Prompt: 有一个某公司职员表&#xff0c;表名为Bank_emp&#xff0c;empno为员工编号&#xff0c;ename为员工姓名…

如果很穷,不妨试一下这个副业,搞钱最快的副业!

前言 相信每一位学习计算机的朋友都想利用自己所学的知识赚点生活费&#xff0c;我也不例外&#xff0c;哈哈哈&#xff0c;学了这么多年&#xff0c;总得让它发挥点价值不是吗。今天就跟大家分享一下我的真实经历&#xff0c;我是如何利用python兼职实现月收入破万的。下面是…

实战 | 使用CNN和OpenCV实现数字识别项目(步骤 + 源码)

导 读 本文主要介绍使用CNN和OpenCV实现数字识别项目,含详细步骤和源码。 前 言 在当今世界,深度学习和图像处理技术正在各个应用领域得到利用。在这篇博文中,我们将使用卷积神经网络 (CNN) 和 OpenCV 库完成数字识别项目。我们将逐步掌握该项目如何执行。 项目准…

自然语言编程系列(三):自然语言编程工具

自然语言编程工具尝试让用户以更接近日常对话的方式描述任务&#xff0c;然后将其自动转换成合适的代码。 自然语言编程工具&#xff08;Natural Language Programming, NLP&#xff09;旨在降低编程门槛&#xff0c;使得不具备传统编程技能的用户能够以他们习惯的日常对话方式…

spark sql官网优化指南

两句话概括 缓存数据调整参数 缓存数据 把数据缓存到内存,spark sql能够只扫描需要列并且会自动压缩数据,占用最小的内存和减小GC压力。这无需多言,内存远远要快于磁盘,spark效率比hive高这个就是一个主要原因。 缓存数据代码spark.catalog.cacheTable("tableName&qu…

Python实现EMV指标计算:股票技术分析的利器系列(2)

Python实现EMV指标计算&#xff1a;股票技术分析的利器系列&#xff08;2&#xff09; 介绍算法解释&#xff1a; 核心代码&#xff1a;rolling函数介绍 完整代码&#xff1a;一定要看 介绍 先看看官方介绍&#xff1a; EMV(简易波动指标&#xff09; 用法 1.EMV 由下往上穿越…

Dynamo根据几何相交对墙体进行分组——群问题整理002

你好&#xff0c;这里是 BIM 的乐趣&#xff0c;我是九哥~ 近期给大家分享一些短平快的小教程&#xff0c;基本都是来自群里面常问的问题&#xff0c;不做过多的介绍了&#xff0c;直接上截图和代码。 问题&#xff1a;002 - 根据几何相交对墙体进行分组 今天分享的&#xff0…

OpenAI取消GPT-4 Turbo每日限制,速率提升一倍;扩散模型的理论基础

&#x1f989; AI新闻 &#x1f680; OpenAI取消GPT-4 Turbo每日限制&#xff0c;速率提升一倍 摘要&#xff1a;OpenAI宣布取消GPT-4 Turbo的每日限制&#xff0c;提升速率限制1倍&#xff0c;每分钟可处理高达150万TPM的数据。 OpenAI解释速率限制对防止API滥用、确保公平访…

用例是独立的-《软件方法》自测题解析38

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 《软件方法》第5章自测题2 8 [ 多选题 ] 根据以下业务序列图&#xff0c;请问属于“一卡通系统”用例的有&#xff1a;  A) 外来办事人员→登记  B) 一卡通系统→判断黑名单 …