设计模式之装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

前言:
两个本想描述一样的意思的词,只因一字只差就让人觉得一个是好牛,一个好搞笑。往往我们去开发编程写代码时也经常将一些不恰当的用法用于业务需求实现中,但却不能意识到。一方面是由于编码不多缺少较大型项目的实践,另一方面是不思进取的总在以完成需求为目标缺少精益求精的工匠精神。
在这里插入图片描述
初看上图感觉装饰器模式有点像俄罗斯套娃、某众汽车🚕,而装饰器的核心就是在不改原有类的基础上给类新增功能。不改变原有类,可能有的小伙伴会想到继承、AOP切面,当然这些方式都可以实现,但是使用装饰器模式会是另外一种思路更为灵活,可以避免继承导致的子类过多,也可以避免AOP带来的复杂性。
在这里插入图片描述
这里模拟的是spring中的类:HandlerInterceptor,实现接口功能SsoInterceptor模拟的单点登录拦截服务。
模拟Spring的HandlerInterceptor

package oom.lm.design;public interface HandlerInterceptor {boolean preHandle(String request, String response, Object handler);}

模拟单点登录功能

package oom.lm.design;public class SsoInterceptor implements HandlerInterceptor{@Overridepublic boolean preHandle(String request, String response, Object handler) {// 模拟获取cookieString ticket = request.substring(1, 8);// 模拟校验return ticket.equals("success");}}

里的模拟实现非常简单只是截取字符串,实际使用需要从HttpServletRequest request对象中获取cookie信息,解析ticket值做校验
用一坨坨代码实现
继承类的实现方式也是一个比较通用的方式,通过继承后重写方法,并发将自己的逻辑覆盖进去。如果是一些简单的场景且不需要不断维护和扩展的,此类实现并不会有什么,也不会导致子类过多。

package oom.lm.design;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class LoginSsoDecorator extends SsoInterceptor {private static Map<String, String> authMap = new ConcurrentHashMap<String, String>();static {authMap.put("huahua", "queryUserInfo");authMap.put("doudou", "queryUserInfo");}@Overridepublic boolean preHandle(String request, String response, Object handler) {// 模拟获取cookieString ticket = request.substring(1, 8);// 模拟校验boolean success = ticket.equals("success");if (!success){return false;}String userId = request.substring(9);String method = authMap.get(userId);// 模拟方法校验return "queryUserInfo".equals(method);}}

以上这部分通过继承重写方法,将个人可访问哪些方法的功能添加到方法中。
测试验证

package oom.lm.design.test;import oom.lm.design.LoginSsoDecorator;
import org.junit.Test;public class ApiTest {@Testpublic void test_LoginSsoDecorator() {LoginSsoDecorator ssoDecorator = new LoginSsoDecorator();String request = "1successhuahua";boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t");System.out.println("登录校验:" + request + (success ? " 放行" : " 拦截"));}}

装饰器模式重构代码
装饰器主要解决的是直接继承下因功能的不断横向扩展导致子类膨胀的问题,而是用装饰器模式后就会比直接继承显得更加灵活同时这样也就不再需要考虑子类的维护。
1:抽象构件角色(Component) - 定义抽象接口
2:具体构件角色(ConcreteComponent) - 实现抽象接口,可以是一组
3:装饰角色(Decorator) - 定义抽象类并继承接口中的方法,保证一致性
4:具体装饰角色(ConcreteDecorator) - 扩展装饰具体的实现逻辑
在这里插入图片描述
装饰器模式模型结构
在这里插入图片描述
抽象类装饰角色

package oom.lm.design;public abstract class SsoDecorator implements HandlerInterceptor {private HandlerInterceptor handlerInterceptor;private SsoDecorator(){}public SsoDecorator(HandlerInterceptor handlerInterceptor) {this.handlerInterceptor = handlerInterceptor;}@Overridepublic boolean preHandle(String request, String response, Object handler) {return handlerInterceptor.preHandle(request, response, handler);}}

在装饰类中有三个重点的地方是:1)继承了处理接口、2)提供了构造函数、3)覆盖了方法preHandle。
装饰角色逻辑实现

package oom.lm.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class LoginSsoDecorator extends SsoDecorator {private Logger logger = LoggerFactory.getLogger(LoginSsoDecorator.class);private static Map<String, String> authMap = new ConcurrentHashMap<String, String>();static {authMap.put("huahua", "queryUserInfo");authMap.put("doudou", "queryUserInfo");}public LoginSsoDecorator(HandlerInterceptor handlerInterceptor) {super(handlerInterceptor);}@Overridepublic boolean preHandle(String request, String response, Object handler) {boolean success = super.preHandle(request, response, handler);if (!success) return false;String userId = request.substring(8);String method = authMap.get(userId);logger.info("模拟单点登录方法访问拦截校验:{} {}", userId, method);// 模拟方法校验return "queryUserInfo".equals(method);}
}

在具体的装饰类实现中,继承了装饰类SsoDecorator,那么现在就可以扩展方法;preHandle
测试验证

package oom.lm.design.test;import oom.lm.design.LoginSsoDecorator;
import oom.lm.design.SsoInterceptor;
import org.junit.Test;public class ApiTest {@Testpublic void test_LoginSsoDecorator() {LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(new SsoInterceptor());String request = "1successhuahua";boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t");System.out.println("登录校验:" + request + (success ? " 放行" : " 拦截"));}}

总结
1:使用装饰器模式满足单一职责原则,你可以在自己的装饰类中完成功能逻辑的扩展,而不影响主类,同时可以按需在运行时添加和删除这部分逻辑。另外装饰器模式与继承父类重写方法,在某些时候需要按需选择,并不一定某一个就是最好。
2:装饰器实现的重点是对抽象类继承接口方式的使用,同时设定被继承的接口可以通过构造函数传递其实现类,由此增加扩展性并重写方法里可以实现此部分父类实现的功能。
就像夏天热你穿短裤,冬天冷你穿棉裤,雨天挨浇你穿雨衣一样,你的根本本身没有被改变,而你的3:需求却被不同的装饰而实现。生活中往往比比皆是设计,当你可以融合这部分活灵活现的例子到代码实现中,往往会创造出更加优雅的实现方式。

好了 至此 设计模式之装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景) 学习结束了 友友们 点点关注不迷路 老铁们!!!!!

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

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

相关文章

使用热冻结数据层生命周期优化在 Elastic Cloud 中存储日志的成本

作者&#xff1a;来自 Elastic Jonathan Simon 收集数据对于可观察性和安全性至关重要&#xff0c;而确保数据能够快速搜索且获得低延迟结果对于有效管理和保护应用程序和基础设施至关重要。但是&#xff0c;存储所有这些数据会产生持续的存储成本&#xff0c;这为节省成本创造…

Node.js事件循环:解锁异步编程的奥秘

Node.js的事件循环是实现高性能、异步编程的关键机制。了解Node.js事件循环的工作原理和使用方法对于开发高效的应用程序至关重要。本文将深入介绍Node.js事件循环的原理、阶段和最佳实践&#xff0c;帮助您充分利用这一强大功能。 Node.js事件循环概述 Node.js事件循环是Node…

Windows docker下载minio出现“Using default tag: latestError response from daemon”

Windows docker下载minio出现 Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded 此类情况&#xff0c;一般为镜像地址问题。 {"registry-mirrors": ["https://docker.re…

20241114软考架构-------软考案例16答案

每日打卡题案例16答案 16.【2017年真题】 难度&#xff1a;简单 阅读以下关于软件架构评估的叙述&#xff0c;在答题纸上回答问题1和问题2.(共25分) 【说明】 某单位为了建设健全的公路桥梁养护管理档案&#xff0c;拟开发一套公路桥梁在线管理系统。在系统的需求分析与架构设…

使用C语言进行信号处理:从理论到实践的全面指南

1. 引言 在现代操作系统中&#xff0c;信号是一种进程间通信机制&#xff0c;它允许操作系统或其他进程向一个进程发送消息。信号可以用来通知进程发生了一些重要事件&#xff0c;如用户请求终止进程、硬件异常、定时器超时等。掌握信号处理技术对于开发健壮、高效的系统程序至…

7天用Go从零实现分布式缓存GeeCache(学习)(2)

参考:https://geektutu.com/post/geecache-day2.html // Cache 是一个 LRU 缓存&#xff08;最近最少使用缓存&#xff09;&#xff0c;它不是并发安全的。 type Cache struct { maxBytes int64 // 缓存的最大字节数 nbytes int64 …

【微服务】Docker 容器化

一、初识Docker 1. 为什么需要 Docker 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会遇到一些问题&#xff1a; 依赖关系复杂&#xff0c;容易出现兼容性的问题开发、测试、生产环境有差异 Docker 如何解决依赖的兼容问题 将应用的Libs&#xff08;…

curl命令提交大json

有个客户需要提交一个4M左右的pdf&#xff0c;接口里传的是pdf字节流base64编码后的字符串。 直接curl -XPOST -d json串 api接口会报 参数过长报错Argument list too long 网上搜了下解决方案把json串放到文本里然后通过json.txt引入参数 这一试不要紧&#xff0c;差点儿导致…

websocket身份验证

websocket身份验证 前言 上一集我们就完成了websocket初始化的任务&#xff0c;那么我们完成这个内容之后就应该完成一个任务&#xff0c;当客户端与服务端连接成功之后&#xff0c;客户端应该主动发起一个身份认证的消息。 身份认证proto 我们看一眼proto文件的内容。 我…

Scala学习记录,case class,迭代器

case class case class创建的对象的属性是不可改的 创建对象&#xff0c;可以不用写new 自动重写&#xff1a;toString, equals, hashCode, copy 自动重写方法&#xff1a;toString,equals,hashCode,copy 小习一下 1.case class 的定义语法是什么 基本形式&#xff1a;case …

mysql中的EXISTS和NOT EXISTS使用详解

本文来编写一个实例说下mysql中的EXISTS和NOT EXISTS使用详解 文章目录 exists用法SQL中in, not in, exists, not exists的区别使用实例本文小结 exists用法 exists: 如果括号内子查询语句返回结果不为空&#xff0c;说明where条件成立&#xff0c;就会执行主SQL语句。如果括号…

HTB:Precious[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机TCP端口进行开放扫描 使用curl访问靶机80端口 使用ffuf爆破一下子域 使用浏览器访问该域名 使用curl访问该域名响应头 使用exiftool工具查看该pdf信息 横向移动 USER_FLAG&#xff1a;adf5793a876a190f0c08b3b6247cec32…

【论文分享】三维景观格局如何影响城市居民的情绪

本次带来一篇SCI论文的全文翻译&#xff01;该论文以上海LivingLine项目为例&#xff0c;探索利用时空Wi-Fi数据分析街道层面的城市活力。 【论文题目】Understanding street-level urban vibrancy via spatial-temporal Wi-Fi data analytics: Case LivingLine Shanghai 【题…

大数据面试题--kafka夺命连环问(前15问)

目录 1、kafka消息发送的流程&#xff1f; 2、Kafka 的设计架构你知道吗 3、Kafka 分区的目的&#xff1f; 4、你知道 Kafka 是如何做到消息的有序性&#xff1f; 5、ISR、OSR、AR 是什么&#xff1f; 6、Kafka 在什么情况下会出现消息丢失&#xff1f; 7、怎么尽可能保…

scala 迭代更新

在Scala中&#xff0c;迭代器&#xff08;Iterator&#xff09;是一种用于遍历集合&#xff08;如数组、列表、集合等&#xff09;的元素而不暴露其底层表示的对象。迭代器提供了一种统一的方法来访问集合中的元素&#xff0c;而无需关心集合的具体实现。 在Scala中&#xff0c…

比ChatGPT更酷的AI工具

相较于寻找比ChatGPT更酷的AI工具&#xff0c;这听起来似乎是个挑战&#xff0c;因为ChatGPT已经以它强大的综合性能在AI界大名鼎鼎。然而&#xff0c;每个工具都有其独特的优势&#xff0c;特别是在特定的应用场景下&#xff0c;其他AI工具可能会展现出与ChatGPT不同的魅力。接…

[极客大挑战 2019]Upload 1

[极客大挑战 2019]Upload 1 审题 看到是一个文件上传类题型。 知识点 一句话木马的注入 知识点详解 一句话木马的原理 eval()函数会将参数作为PHP代码进行执行&#xff0c;因此通过eval()函数中的参数v提交要执行的代码即可完成漏洞利用。语句中的符号作用是可以屏蔽函数…

Redis缓存雪崩、击穿、穿透技术解析及解决方案

在使用 Redis 缓存时&#xff0c;经常会遇到一些异常问题。 概括来说有 4 个方面&#xff1a; 缓存中的数据和数据库中的不一致&#xff1b;缓存雪崩&#xff1b;缓存击穿&#xff1b;缓存穿透。 关于第一个问题【缓存中的数据和数据库中的不一致】&#xff0c;在之前的文章…

[C++11] 包装器 : function 与 bind 的原理及使用

文章目录 functionstd::function 的基本语法使用 std::function 包装不同的可调用对象function包装普通成员函数为什么要传入 this 指针参数&#xff1f;传入对象指针与传入对象实例的区别 例题 &#xff1a;150. 逆波兰表达式求值 - ⼒扣&#xff08;LeetCode&#xff09; bin…

企业一站式管理系统odoo的研究——系统搭建

大纲 1. 环境准备1.1 安装操作系统1.2 更新操作系统1.3 配置用户组和用户1.3.1 创建用户组 odoo1.3.2. 创建用户 odoo1.3.3. 设置用户 odoo 的密码1.3.4. 验证用户和组1.3.5. 将用户 odoo 添加到添加sudo组&#xff1a;1.3.6. 切到odoo用户 2. 安装 Odoo1. 安装依赖项目2.2. 安…