Java 和 SpringBoot 中的设计模式 详解

一、建造者模式

发生场景

假如有一结果api结果返回值的类Person,其在代码中频繁被使用。如果要使用它,一般的方法是:

public class Main {public static void main(String[] args) {//方法1,使用全量的构造函数Person person1 = new Person("Tom", 28, "Male");//方法2,使用空的构造函数加setter函数赋值Person person2 = new Person();person2.setName("Tom");person2.setAge(28);person2.setGender("Male");}
}//--》产品
class Person {private String name;private int age;private String gender;public Person() {}public Person(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setGender(String gender) {this.gender = gender;}
}

这两种使用方法的弊端有:

(1)方法一:当只需要部分参数的时候需要再定义个构造函数(比如失败的情况只需要code和message,结果肯定是空,因此不需要data),且一旦参数较多,则构造函数冗长

(2)方法二setter冗长

使用建造者模式优化上述场景

//使用方法--》指导者
Person person = Person.builder().name("Tom")   //相当于setName("Tom"),只是方法名取name.age(28).gender("Male").build();//--》产品
public class Person {private String name;private int age;private String gender;//⑤public Person(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}//①public static PersonBuilder builder() {return new PersonBuilder();}
}// Java 实现--》建造者
public class PersonBuilder {private String name;private int age;private String gender;//②空构造器public PersonBuilder() {}//③然后使用setter方法进行设置public PersonBuilder name(String name) {this.name = name;return this;  //方法返回当前对象的引用。这样可以支持方法链式调用。//通过返回当前对象的引用,可以在一个语句中连续调用对象的方法,而无需每次调用都创建一个新的对象。}public PersonBuilder age(int age) {this.age = age;return this;}public PersonBuilder gender(String gender) {this.gender = gender;return this;}//④public Person build() {return new Person(name, age, gender);}
}

应用案例

Lombok插件的@Builder注解

//使用
Person person = Person.builder().name("Tom").age(28).gender("Male").build();//lombok优化后
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Person {private String name;private int age;private String gender;
}

二、代理模式

避免客户端直接访问真实对象,必须通过代理对象访问真实对象。

好处:①在代理对象中限制访问权限(权限校验);②在代理对象中扩展功能(日志记录)

静态代理

  1. 代理对象真实对象实现了同一个接口,这样代理对象就具有了和真实对象一样的同名方法
  2. 代理对象持有真实对象的实例(代理对象构造器输入参数为公共接口,这样可以代理多个实现类)
  3. 调用时使用代理对象的方法,在代理对象的方法里再调用真实对象同名方法和增加一些扩展操作

缺点:

  • 代理对象的一个接口只服务于一种类型的对象,如果要代理的类很多,势必要为每一种类都进行代理,在程序规模稍大时静态代理代理类就会过多会造成代码混乱
  • 2、如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度。

动态代理

1.JDK 动态代理(反射)——目标对象实现了接口

  1. 定义一个接口及其实现类;
  2. 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;
//公共接口
public interface SmsService {String send(String message);
}//真实对象
public class SmsServiceImpl implements SmsService {public String send(String message) {System.out.println("send message:" + message);return message;}
}//代理对象(自定义 InvocationHandler)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class DebugInvocationHandler implements InvocationHandler {/*** 代理类中的真实对象*/private final Object target;public DebugInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {//调用方法之前,我们可以添加自己的操作System.out.println("before method " + method.getName());Object result = method.invoke(target, args);//调用方法之后,我们同样可以添加自己的操作System.out.println("after method " + method.getName());return result;}
}//代理对象的工厂类
public class JdkProxyFactory {public static Object getProxy(Object target) {return Proxy.newProxyInstance(              //创建代理对象target.getClass().getClassLoader(), // 目标类的类加载target.getClass().getInterfaces(),  // 代理需要实现的接口,可指定多个new DebugInvocationHandler(target)   // 代理对象对应的自定义 InvocationHandler);}
}//实际使用
SmsService smsServiceProxy = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
smsServiceProxy.send("java");

2.CGLIB 动态代理机制(反射+继承)——目标对象没有实现接口

  1. 定义一个类;
  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
  3. 通过 Enhancer 类的 create()创建代理类;
//真实对象(类和方法都不能是final的,因为CGLIB代理用到了继承)
public class SmsService {public String send(String message) {System.out.println("send message:" + message);return message;}
}//代理对象(自定义 MethodInterceptor)
public class MethodInterceptor implements MethodInterceptor {//被代理对象private Object target;public MethodInterceptor(Object target) {this.target = target;}public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("CGLib商店打广告!");//调用原来方法Object invoke = method.invokeSuper(target, objects);System.out.println("CGLib商店做售后!");return invoke;}
}//代理对象的工厂类
public class CGlibFactoryProxy {public Object createProxy(Object target){this.target = target;//创建代理对象Enhancer enhancer = new Enhancer();//设置父类,以便 CGLIB 去生成该类的子类enhancer.setSuperclass(this.target.getClass());//设置方法回调MethodInterceptor实现,你可以认为是设置增强方法enhancer.setCallback(new MethodInterceptor());//返回代理对象return enhancer.create();}
}//实际使用
CGlibFactoryProxy factoryProxy = new CGlibFactoryProxy();
SmsService smsServiceProxy = (SmsService) factoryProxy.createProxy(new SmsService());
smsServiceProxy.send("java");

3.应用案例

Spring 框架的 AOP 使用了动态代理模式来实现切面编程。通过代理,Spring 能够在目标对象的方法执行前、执行后或抛出异常时插入切面逻辑,而不需要修改原始代码。

  • (切点)在哪里切入,也就是权限校验等非业务操作在哪些业务代码中执行。
  • (处理时机)在什么时候切入,是业务代码执行前还是执行后。
  • (处理内容)切入后做什么事,比如做权限校验、日志记录等。

Joint point:一个方法的执行或者一个异常的处理。

Weaving:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。

基于AspectJ实现AOP操作

Spring框架一般都是基于AspectJ实现AOP操作。AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作。

1.基于xml配置文件实现

2.基于注解方式实现(使用,重要)

//切面类
@Aspect
@Component
public class UserProxy {//1.相同切入点抽取@Pointcut(value = "execution(* com.jin.aopanno.User.add(..))")public void pointdemo(){}@Before(value = "pointdemo()")public void before(){System.out.println("before ...");}//2.不同切入点抽取//前置通知(value = 切入点表达式)@Before(value = "execution(* com.jin.aopanno.User.add(..))")public void before(){System.out.println("before ...");}//3.自定义注解@Before("@annotation(com.easychat.annotation.GlobalInterceptor)")public void before(){System.out.println("before ...");}private void checkLogin(Boolean checkAdmin) {}
}//自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GlobalInterceptor {//校验登录boolean checkLogin() default true;
}

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

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

相关文章

MF173:将多个工作表转换成PDF文件

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

三、初识C语言(3)

1.操作符 &#xff08;1&#xff09;算术操作符 - * / % 商 余&#xff08;取模&#xff09; 小算法&#xff1a; 若a<b&#xff0c;则a%b a 若a%b c&#xff0c;则0 < c < b-1 若两个int 类型数相除&#xff0c;结果有小数会被舍弃。 保留小数…

LeetCode岛屿的最大面积(深度搜索)/什么是深搜,简单案例回顾图用邻接表实现图的深度优先遍历。

看这道题不懂深度搜索的可以看看下面讲述 岛屿的最大面积 解题思路 代码 class Solution {int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) {//确定边界if((cur_i >0 && cur_i < grid.size()) && (cur_j >0 &&…

开机出现grub无法进入系统_电脑开机出现grub解决方法

最近有小伙伴问我电脑开机出现grub无法进入系统怎么回事&#xff1f;电脑开机出grub的情况有很多&#xff0c;电脑上安装了Linux和Win10双系统&#xff0c;但是由于格式化删除了Linux之后&#xff0c;结果win10开机了之后&#xff0c;直接显示grub&#xff1e;&#xff0c;无法…

MySQL事务管理(上)

MySQL注定会被多个用户或者客户端&#xff0c;因为MySQL存的是数据&#xff1b;MySQL内部使用的是多线程的方式来实现数据的存储工作&#xff1b; 前言 CURD不加控制&#xff0c;会有什么问题&#xff1f; 如今有个数据库里面是火车票售票系统所对应的数据库表&#xff1b;M…

.net6 core Worker Service项目,使用Exchange Web Services (EWS) 分页获取电子邮件收件箱列表,邮件信息字段

Program.cs 安装包&#xff1a;Microsoft.AspNetCore.Hosting.WindowsServices、Microsoft.Extensions.Hosting、Microsoft.Extensions.Hosting.WindowsServices、Microsoft.Extensions.Logging.Log4Net.AspNetCore 新建Configs/log4net.config using Com.Chinahorn.Exchange.W…

ubantu22.04安装OceanBase 数据库

1、管理员启动cmd,运行 sudo bash -c "$(curl -s https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/service/installer.sh)" 2、提示如下代表安装完成 3、修改数据库配置文件的密码 sudo vim /etc/oceanbase.cnf 然后保存退…

正则表达式(Ⅰ)——基本匹配

学习练习建议 正则表达式用途非常广泛&#xff0c;各种语言中都能见到它的身影&#xff08;js&#xff0c;java&#xff0c;mysql等&#xff09; 正则表达式可以快读校验/生成/替换符合要求的模式的字符串&#xff0c;而且语法通俗易懂&#xff0c;所以应用广泛 学习链接&am…

css前端面试题

1.什么是css盒子模型&#xff1f; 盒子模型包含了元素内容&#xff08;content&#xff09;、内边距&#xff08;padding&#xff09;、边框&#xff08;border&#xff09;、外边距&#xff08;margin&#xff09;几个要素。 标准盒子模型和IE盒子模型的区别在于其对元素的w…

C++模板进阶和模板链接错误的解决

小编在学习模板进阶之后&#xff0c;觉得模板的内容很有用&#xff0c;所以今天带给大家的内容是模板进阶的所有内容&#xff0c;内容包括模板的使用&#xff0c;模板的特化&#xff0c;模板的全特化&#xff0c;模板的偏特化&#xff0c;模板链接时候会出现的链接错误及解决方…

Ubuntu系统SSH免密连接Github配置方法

Ubuntu系统SSH免密连接Github配置方法 一、相关介绍1.1 Ubuntu简介1.2 Git简介1.3 Github简介 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、Git本地环境配置工作4.1 安装Git工具4.2 创建项目目录4.3 …

STM32被拔网线 LWIP的TCP无法重连解决方案

目录 一、问题描述 二、项目构成 三、问题解决 1.问题代码 2.解决思路 3.核心代码&#xff1a; 四、完整代码 1.监测网口插入拔出任务 2.TCP任务 3.创建tcp任务 4.删除tcp任务 五、总结 一、问题描述 最近遇到一个问题&#xff0c;就是我的stm32设备作为tcp客户端…

AndroidStudio与手机进行无线调试

(一)、前提条件 一部手机一条USB数据线一部电脑手机和电脑连接到同一个 Wifi开启手机的USB调试功能开启手机的无线调试功能 (二)、操作步骤 1、 将手机和电脑用USB数据线连接 2、 打开 终端&#xff0c;输入 adb devices ,查看手机和电脑是否连接成功。如下图&#xff1a; 2、…

Linux驱动开发-06蜂鸣器和多组GPIO控制

一、控制蜂鸣器 1.1 控制原理 我们可以看到SNVS_TAMPER1是这个端口在控制着蜂鸣器,同时这是一个PNP型的三极管,在端口输出为低电平时,蜂鸣器响,在高电平时,蜂鸣器不响 1.2 在Linux中端口号的控制 gpiochipX:当前SoC所包含的GPIO控制器,我们知道I.MX6UL/I.MX6ULL一共包…

Atom - hackmyvm

简介 靶机名称&#xff1a;Atom 难度&#xff1a;简单 靶场地址&#xff1a;https://hackmyvm.eu/machines/machine.php?vmAtom 本地环境 虚拟机&#xff1a;vitual box 靶场IP&#xff08;Atom&#xff09;&#xff1a;192.168.56.101 跳板机IP(windows 11)&#xff1…

多显示器,如何快速切换电脑显示模式!

​一般在使用多显示器的情况下,可能我们要根据不同的工作需求来动态调整相适应的Windows显示模式,像扩展模式、复制模式、单显示器等模式。调整相应的模式方法也不止一种,下面一起了解下不同的方法如何快速操作实现! 快捷键法(WIN+P) 同时按下键盘徽标键WIN+P,会弹出个选…

微软发布iOS/安卓正式版Designer应用,AI修图功能助力创意设计

一、Microsoft Designer应用正式上线 AITOP100平台获悉&#xff0c;微软一直致力于为用户提供优质的创意工具&#xff0c;此次推出的Microsoft Designer应用正是其在移动端的重要布局。这款应用已正式上线iOS、Android、Windows和网页版本&#xff0c;满足不同用户的需求。微软…

高性能系统架构设计之:多级缓存

前言 为了提高系统的性能&#xff0c;一般会引入“缓存机制”&#xff0c;将部分热点数据存入缓存中&#xff0c;用空间换取时间&#xff0c;以达到快速响应的目的。 其实&#xff0c;缓存的应用远远不止存在于服务层&#xff08;传统的Redis缓存&#xff09;&#xff0c;从客户…

虚拟试衣人像合成新SOTA!IMAGDressing-v1:ControlNet和IP-Adapter的最佳拍档

文章链接&#xff1a;https://arxiv.org/pdf/2407.12705 github链接&#xff1a;https://imagdressing.github.io/ Demo试用&#xff1a;https://sf.dictdoc.site/ 亮点直击 为商家引入了一项新的虚拟试衣&#xff08;VD&#xff09;任务&#xff0c;并设计了一个综合亲和力测量…

最新缺失msvcp140.dll的多种解决方法,有效解决电脑dll问题

msvcp140.dll 是一个关键的动态链接库&#xff08;DLL&#xff09;文件&#xff0c;属于 Microsoft Visual C 2015 Redistributable 的一部分。它为使用 Microsoft Visual C 编译的应用程序提供了运行时支持&#xff0c;确保这些应用程序能够正常运行。以下是对 msvcp140.dll 的…