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

Java 设计模式

Java后端常用设计模式总览表

模式核心思想Spring / Spring Boot应用手写实现核心
单例模式 (Singleton)一个类只有一个实例,提供全局访问点Spring容器中的默认Bean都是单例管理volatile + synchronized 双重检查锁定,懒加载单例
工厂模式 (Factory)统一管理和创建对象,不暴露具体创建逻辑ApplicationContext/BeanFactory 统一管理Bean创建定义工厂类,使用if-else或注册表管理产品实例化
建造者模式 (Builder)分步骤、链式构建复杂对象,分离构建和表示Lombok的@Builder注解,客户端配置如OkHttpClient写Builder内部静态类,链式调用设置属性,最后build
原型模式 (Prototype)复制已有对象,避免重新new实例@Scope("prototype") 让Bean每次getBean都生成新实例实现Cloneable接口,重写clone()方法深/浅拷贝
代理模式 (Proxy)通过代理对象控制访问、扩展目标对象功能Spring AOP(@Transactional、@Aspect等)JDK动态代理(接口)/ CGLIB子类代理(继承+增强)
装饰器模式 (Decorator)动态添加功能,不修改原对象结构Servlet Filter链、Spring MVC拦截器链(增强请求)抽象组件接口+抽象装饰器类+具体装饰器层层包裹
适配器模式 (Adapter)将一个接口转换成另一个兼容的新接口Spring MVC HandlerAdapter适配不同类型Controller定义适配器类,包装老接口对象,实现新接口
外观模式 (Facade)提供统一高层接口,简化复杂子系统调用Service层聚合调用多个子系统服务(FacadeService)定义一个Facade类,组合子系统并统一暴露简洁接口
策略模式 (Strategy)封装一系列可互换的算法或行为,动态切换Spring Security中多种认证策略,支付策略选择策略接口+多策略实现+上下文Context动态持有策略
模板方法模式 (Template Method)固定流程结构,子类实现细节步骤JdbcTemplate/RestTemplate/RedisTemplate等抽象父类定义流程+抽象方法留给子类实现
责任链模式 (Chain of Responsibility)请求沿链传递,每个节点决定处理或传递Servlet FilterChain、HandlerInterceptor链Handler接口+设置next+handle递归链式传递
观察者模式 (Observer)一对多通知机制,主题变化自动通知观察者Spring事件机制(ApplicationEventPublisher+@EventListener)Subject接口+Observer接口+列表管理观察者,通知更新

✅ 1. 单例模式(Singleton Pattern)


✏️ 基本概念

单例模式的定义是:

保证一个类在整个系统中只有一个实例,并且提供一个全局访问点

Spring容器默认就是单例模式,通过IoC管理Bean,确保一个Bean一个实例,方便全局统一调度。

简单说,就是一个类只new一次,后面都复用同一个对象


✏️ 为什么要用单例模式?

  • 节省内存(避免反复创建同一对象)

  • 保持全局统一性(比如日志类、缓存管理器、数据库连接池)

  • 控制共享资源(保证线程安全)


✏️ 在Spring中的应用

在Spring中:

  • 默认情况下,所有@Bean都是单例模式管理的

  • 只要一个类被注册到Spring容器里(比如加了@Component@Service@Controller),

  • Spring容器在启动的时候就创建一个实例,整个容器里共享这一份实例


✏️ 示例讲解

@Service
public class UserService {public void print() {System.out.println("UserService实例: " + this);}
}

调用代码:

@Autowired
private UserService userService1;@Autowired
private UserService userService2;public void test() {userService1.print();userService2.print();
}

输出结果

UserService实例: com.example.UserService@1b6d3586
UserService实例: com.example.UserService@1b6d3586
  • 说明userService1userService2同一个实例

✏️手写示例

volatile + synchronized(双重检查锁定)

public class Singleton {private static volatile Singleton instance;private Singleton() {// 初始化逻辑}public static Singleton getInstance() {if (instance == null) {  // 第一次检查synchronized (Singleton.class) {if (instance == null) {  // 第二次检查instance = new Singleton();}}}return instance;}
}

✅ 2. 工厂模式(Factory Pattern)


✏️ 基本概念

工厂模式的定义是:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

简单说,就是把对象的创建过程交给工厂统一管理,而不是自己new对象。


✏️ 为什么要用工厂模式?

  • 解耦对象的创建过程和使用过程

  • 统一集中管理对象创建,便于维护

  • 可以根据不同参数返回不同子类实例(多态)


✏️ 在Spring中的应用

在Spring中:

  • BeanFactory是Spring容器的最基本工厂接口。

  • ApplicationContext是BeanFactory的子接口,提供了更强大的功能。

Spring容器就是一个超大的工厂,你只需要调用getBean(),容器就帮你创建对象并注入依赖了。


✏️ 示例讲解

Spring工厂使用例子:

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = context.getBean(UserService.class);
userService.print();
  • AnnotationConfigApplicationContext是工厂(Factory)。

  • getBean()就是工厂方法,通过Bean的名字或者类型拿到对象

  • 创建、初始化、依赖注入,这些细节都隐藏了。

内容对应
接口:定义了创建对象的方法ApplicationContext 定义了 getBean() 等方法
子类:决定具体如何创建对象AnnotationConfigApplicationContext 决定通过注解扫描来实例化哪些Bean
使用时,只关心接口,不关心细节调用 context.getBean(UserService.class),不用关心UserService是怎么被创建出来的

✏️手写示例

public class CarFactory {public static Car getCar(String type) {if ("bmw".equals(type)) {return new BmwCar();} else if ("audi".equals(type)) {return new AudiCar();}return null;}
}
  • 外部只管调用CarFactory.getCar("bmw")

  • 不关心Car是怎么new出来的


✅ 3. 建造者模式(Builder Pattern)


✏️ 基本概念

建造者模式的定义是:

将一个复杂对象的构建过程分步进行,并且允许构建过程和对象本身解耦。

简单说,就是链式调用,一步步设置参数,最后一次性build出对象


✏️ 为什么要用建造者模式?

  • 对象属性太多,构造函数太复杂时,避免构造方法参数过长问题

  • 使对象创建过程清晰有条理

  • 支持不同顺序、不同属性构建对象(灵活)


✏️ 在Spring Boot/Lombok中的应用

Spring Boot项目里常常结合Lombok的@Builder注解来使用建造者模式。

比如定义一个实体类:

@Data
@Builder
public class User {private String name;private Integer age;private String email;
}

调用时:

User user = User.builder().name("Tom").age(18).email("tom@example.com").build();

优势:

  • 不需要自己写冗长的构造器

  • 不需要记得属性顺序

  • 可读性极强


✏️手写示例

public class User {private String name;private Integer age;private User(Builder builder) {this.name = builder.name;this.age = builder.age;}public static class Builder {private String name;private Integer age;public Builder name(String name) { this.name = name; return this; }public Builder age(Integer age) { this.age = age; return this; }public User build() { return new User(this); }}
}

✅ 4. 原型模式(Prototype Pattern)


✏️ 基本概念

原型模式的定义是:

通过复制已有的对象来创建新的对象,而不是通过new新的实例。

Spring通过@Scope("prototype")实现了原型模式,让Bean可以按需每次创建一个新实例,而不是单例复用。

简单说,就是复制一份已有对象的副本


✏️ 为什么要用原型模式?

  • new一个新对象成本高时,用复制可以节省资源。

  • 对象初始化复杂时,可以直接clone已有对象。

  • Spring容器中,有时候需要每次getBean()都返回新的实例。


✏️ 在Spring中的应用

在Spring中,如果一个Bean标注了@Scope("prototype")

  • 每次从容器拿Bean,Spring都会新建一个实例

  • 而不是像单例那样复用。

示例:

@Component
@Scope("prototype")
public class OrderService {
}

调用:

@Autowired
private OrderService orderService1;@Autowired
private OrderService orderService2;

输出对比:

orderService1 = com.example.OrderService@1b6d3586
orderService2 = com.example.OrderService@2a1f58b6

可以看到,orderService1orderService2不同实例


✏️手写示例

public class User implements Cloneable {private String name;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

通过clone()方法复制对象,而不是new。

✅ 5. 代理模式(Proxy Pattern)

代理模式的本质是:

不直接访问目标对象,而是通过代理对象间接访问目标对象,并且在访问前后可以增加一些额外操作。

代理模式通过代理对象统一管理对目标对象的访问,实现功能增强和解耦。Spring AOP就是最典型的应用。

  • 代理对象目标对象实现相同接口或继承相同父类。

  • 客户端不感知目标对象变化,所有增强逻辑都由代理完成。

  • 本质是控制访问 + 功能增强


✏️ 为什么要用代理模式?

  • 在目标对象执行前后加入通用逻辑(日志、权限控制、事务管理)

  • 隐藏目标对象的细节,隔离调用者和被调用者

  • 延迟加载、远程代理、保护访问等


✏️ Spring 中的应用

Spring AOP(面向切面编程)核心就是基于代理模式!

当你在Spring中使用如@Transactional、@Async、@Cacheable、@Aspect等功能时, 实际上Spring会:

  • 创建一个代理对象来代替你的目标对象。

  • 所有方法调用都会先进入代理,再决定是否增强(比如加事务、异步执行等)。


AOP代理的具体实现

类型说明
JDK动态代理基于接口代理,只能代理接口方法
CGLIB代理继承目标类,重写方法代理,没有接口也能代理

例子(SpringBoot中)

 

调用过程实际上是:

 

代理对象帮我们织入了事务开启/提交的逻辑。

✏️手写示例

方法一:JDK动态代理(基于接口)

定义接口:

public interface UserService {void addUser();
}

实现接口:

public class UserServiceImpl implements UserService {@Overridepublic void addUser() {System.out.println("新增用户");}
}

定义代理逻辑:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class UserServiceProxy {public static UserService createProxy(UserService target) {return (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法执行前增强逻辑...");Object result = method.invoke(target, args);System.out.println("方法执行后增强逻辑...");return result;}});}
}

使用代理:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class UserServiceProxy {public static UserService createProxy(UserService target) {return (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法执行前增强逻辑...");Object result = method.invoke(target, args);System.out.println("方法执行后增强逻辑...");return result;}});}
}
public class Main {public static void main(String[] args) {UserService target = new UserServiceImpl();UserService proxy = UserServiceProxy.createProxy(target);proxy.addUser();}
}

输出结果

方法执行前增强逻辑...
新增用户
方法执行后增强逻辑...

方法二:自己手写静态代理(和CGLIB动态代理相似)

静态代理CGLIB 动态代理
生成代理类的时机编译时期(代码阶段就有)运行时期(根据目标类即时生成字节码)
是否需要手写代理类是,开发者需要显式写一个代理类否,由框架(如 CGLIB)自动生成
代理类的数量代理一个类就要写一个代理类可以动态为任意类生成代理,不需要事先知道

为什么你觉得 CGLIB 像静态代理?

因为 CGLIB 的底层原理是:

  • 给目标类创建一个子类

  • 然后重写父类的方法,

  • 再在方法前后加逻辑(比如AOP切面),

  • 最后调用 super.method()来执行原来的逻辑。

这种重写+调用 super 的模式,看起来和我们手动写静态代理类很像,比如手写:

public class UserServiceProxy extends UserService {@Overridepublic void save() {System.out.println("before...");super.save();System.out.println("after...");}
}

CGLIB底层生成的字节码跟这种继承加增强的思路非常像。

但是生成动作是运行时动态完成的,而手写静态代理是编译期就固定好的源代码,这是根本区别!


✅ 6. 装饰器模式(Decorator Pattern)

装饰器模式的本质是:

在不修改原有类的基础上,动态地为对象添加新的功能。

  • 装饰器和原对象实现相同接口

  • 装饰器持有原对象引用,并在调用原方法前后增加逻辑。

  • 可以灵活叠加多个装饰器,功能组合不受限制。


✏️ 为什么要用装饰器模式?

  • 需要动态添加、扩展类的功能。

  • 不改变原有对象结构,不影响已有代码。

  • 职责单一,每个装饰器只专注于一类功能增强。


✏️ Spring / Spring Boot中的应用示例

(1)Servlet Filter链(FilterChain)

Servlet 容器(如 Tomcat)处理一个 HTTP 请求时,会:

  • 创建一个 FilterChain 对象(内部保存所有配置好的 Filter 列表)。

  • 按照顺序调用每个 Filter 的 doFilter() 方法。

  • 每个 Filter 自己选择:

    • 是否继续调用 chain.doFilter(request, response)

    • 在调用前后加逻辑。

典型Filter结构:

public class MyFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("Filter 前置处理");chain.doFilter(request, response);  // 继续调用下一个Filter或目标ServletSystem.out.println("Filter 后置处理");}
}

底层原理(Tomcat中)

Tomcat 中 ApplicationFilterChain 类的源码大概逻辑是:

public class ApplicationFilterChain implements FilterChain {private List<Filter> filters;private int pos = 0; // 当前执行到第几个Filterpublic void doFilter(ServletRequest request, ServletResponse response) {if (pos < filters.size()) {Filter currentFilter = filters.get(pos++);currentFilter.doFilter(request, response, this);} else {// 所有Filter执行完了,真正调用目标Servletservlet.service(request, response);}}
}

每个Filter调用完自己的逻辑后,再调用chain.doFilter,递归推进,形成前后增强。

  • 每个Filter不修改原Servlet

  • 可以动态添加新的Filter增强功能;

  • Filter和Servlet都基于ServletRequest/ServletResponse接口约定,保证了统一性。


(2)Spring MVC的HandlerInterceptor链

Spring MVC 收到请求后,会执行:

  • DispatcherServlet -> HandlerMapping -> 获取到一个 HandlerExecutionChain

  • HandlerExecutionChain 内部保存了很多 HandlerInterceptor

  • 调用每个拦截器的 preHandle() 方法。

  • 如果全部返回 true,继续执行真正的 Controller。

  • Controller执行完成后,依次倒序调用拦截器的 postHandle()afterCompletion()

拦截器基本结构:

public class MyInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("前置拦截逻辑");return true; // 继续流程}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("后置拦截逻辑");}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("请求完成后的清理逻辑");}
}

 ✏️手写示例

// 抽象组件(统一接口)
public interface Component {void operation();
}// 具体组件(核心功能)
public class ConcreteComponent implements Component {public void operation() {System.out.println("核心功能");}
}// 抽象装饰器(持有Component引用)
public abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}
}// 具体装饰器A
public class DecoratorA extends Decorator {public DecoratorA(Component component) {super(component);}public void operation() {System.out.println("功能A增强之前");component.operation();  // 调用原对象方法System.out.println("功能A增强之后");}
}// 具体装饰器B
public class DecoratorB extends Decorator {public DecoratorB(Component component) {super(component);}public void operation() {System.out.println("功能B增强之前");component.operation();System.out.println("功能B增强之后");}
}
  • 核心组件(ConcreteComponent)负责最基础的逻辑;

  • 装饰器(ConcreteDecorator)持有原组件引用在调用前后加功能

  • 可以嵌套多个装饰器动态叠加功能。

✅ 7. 适配器模式(Adapter Pattern)

适配器模式的本质是:

将一个类的接口转换成客户希望的另一个接口,解决接口不兼容问题。

  • 适配器是一个中间层。

  • 外部系统调用的是统一接口,不需要关心内部老接口、旧实现。

  • 包装原对象,把它“适配”成新的标准。


✏️ 为什么要用适配器模式?

  • 兼容老系统和新系统(让不同接口风格能互通)

  • 重用已有类(不改动老类源码)

  • 降低代码耦合度(通过中间适配)


✏️ 在Spring / Spring Boot中的应用示例

Spring MVC 中的 HandlerAdapter

  • Spring MVC允许开发者用不同风格的Controller编写业务逻辑(比如传统的Controller类、Rest风格、HttpRequestHandler等)。每种Controller风格调用方式不同,但DispatcherServlet要统一调用。

  • DispatcherServlet调用HandlerMapping(处理器映射器)找到Handler。通常,Handler是一个Controller方法,即:一个带有@RequestMapping@PostMapping等注解的方法。

  • 拿到Handler之后,DispatcherServlet调用HandlerAdapter(处理器适配器)。HandlerAdapter负责真正执行Handler。因为Handler可能是不同风格的(比如普通Controller,还是Rest风格Controller),需要一个适配器统一调用。

核心接口:

public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

 ✏️手写示例

老系统的播放器只能播放MP3 (OldPlayer)

新系统标准接口要求播放MP4 (NewPlayer)


定义老接口(不改动它):

public interface OldPlayer {void playMp3(String fileName);
}

老播放器实现:

public class OldMp3Player implements OldPlayer {@Overridepublic void playMp3(String fileName) {System.out.println("播放老式MP3:" + fileName);}
}

定义新接口:

public interface NewPlayer {void playMp4(String fileName);
}

写一个适配器(Adapter),包装老接口,适配新接口:

public class PlayerAdapter implements NewPlayer {private OldPlayer oldPlayer;public PlayerAdapter(OldPlayer oldPlayer) {this.oldPlayer = oldPlayer;}@Overridepublic void playMp4(String fileName) {System.out.println("适配器转换中...");oldPlayer.playMp3(fileName);}
}

使用适配器:

public class Main {public static void main(String[] args) {OldPlayer oldPlayer = new OldMp3Player();NewPlayer newPlayer = new PlayerAdapter(oldPlayer);newPlayer.playMp4("test.mp3");}
}

✅8. 外观模式(Facade Pattern)

外观模式的本质是:

为一组复杂子系统提供一个统一的、高层次的接口,简化客户端对子系统的使用。

简单理解:

  • 内部可能很复杂(好多类、好多服务互相调用)。

  • 但是对外,只暴露一个简单易用的入口

  • 客户端不需要知道内部细节,只管用外观类。


✏️ 为什么用外观模式?

  • 简化调用流程,屏蔽内部复杂性

  • 降低模块之间的耦合

  • 更易于维护和扩展


✏️ Spring / Spring Boot中的应用示例

在实际项目中,Service层经常使用外观模式:

  • 将多个Service组合在一个统一的Facade服务里。

  • Controller只调用Facade,不关心内部细节。


例子:电商系统下单逻辑

涉及多个子系统:

子系统功能
OrderService创建订单
PaymentService支付订单
InventoryService减库存
LogisticsService安排发货

如果Controller自己依次调用这些子系统,代码又长又乱!

于是写一个外观服务统一封装:

@Service
public class OrderFacadeService {@Autowiredprivate OrderService orderService;@Autowiredprivate PaymentService paymentService;@Autowiredprivate InventoryService inventoryService;@Autowiredprivate LogisticsService logisticsService;public void placeOrder(OrderRequest request) {orderService.createOrder(request);paymentService.payOrder(request.getOrderId());inventoryService.deductStock(request.getProductId());logisticsService.arrangeShipment(request.getOrderId());}
}

Controller调用变得超简单:

@RestController
public class OrderController {@Autowiredprivate OrderFacadeService orderFacadeService;@PostMapping("/order")public void createOrder(@RequestBody OrderRequest request) {orderFacadeService.placeOrder(request);}
}

✅ 9. 策略模式(Strategy Pattern)

策略模式的本质是:

定义一系列算法(行为),将它们封装起来,使它们可以互相替换使用。

核心思想:

  • 不同策略可以动态切换。

  • 行为由策略对象决定,不由调用者写死。

  • 避免if...else...switch...case...代码膨胀。


✏️ 为什么要用策略模式?

  • 将算法/行为从使用者中分离,更灵活更可扩展。

  • 减少代码耦合,新策略只需新增类,不改动原有代码(符合开闭原则)。

  • 运行时可以动态切换策略,满足不同业务场景。


✏️ Spring / Spring Boot中的应用示例

(1)Spring Security中的认证机制

Spring Security允许通过不同认证策略(用户名密码登录、OAuth2登录、JWT认证等),
每种认证方式就是一种策略,由AuthenticationProvider接口统一约定。

核心接口:

public interface AuthenticationProvider {Authentication authenticate(Authentication authentication) throws AuthenticationException;
}

不同实现:

  • DaoAuthenticationProvider:基于数据库用户名密码认证

  • JwtAuthenticationProvider:基于JWT Token认证

  • OAuth2AuthenticationProvider:基于OAuth2认证

Spring Security会根据具体情况选择不同的AuthenticationProvider策略执行认证。


(2)实际业务开发中常见使用(举例)

比如你开发一个支付系统:

  • 有微信支付(WeChatPayStrategy)

  • 有支付宝支付(AliPayStrategy)

  • 有银联支付(UnionPayStrategy)

不同支付方式就是不同的策略!

 ✏️手写示例

场景模拟:支付策略系统


定义策略接口:

public interface PayStrategy {void pay(double amount);
}

定义不同策略实现:

public class WeChatPayStrategy implements PayStrategy {@Overridepublic void pay(double amount) {System.out.println("使用微信支付:" + amount + "元");}
}

微信支付:

public class AliPayStrategy implements PayStrategy {@Overridepublic void pay(double amount) {System.out.println("使用支付宝支付:" + amount + "元");}
}

支付宝支付:

public class PayContext {private PayStrategy payStrategy;public PayContext(PayStrategy payStrategy) {this.payStrategy = payStrategy;}public void executePay(double amount) {payStrategy.pay(amount);}
}

定义上下文类(Context),持有一个策略对象:

public class PayContext {private PayStrategy payStrategy;public PayContext(PayStrategy payStrategy) {this.payStrategy = payStrategy;}public void executePay(double amount) {payStrategy.pay(amount);}
}

使用策略:

public class Main {public static void main(String[] args) {PayContext context = new PayContext(new WeChatPayStrategy());context.executePay(100.0);context = new PayContext(new AliPayStrategy());context.executePay(200.0);}
}

输出结果:

使用微信支付:100.0元
使用支付宝支付:200.0元

✅ 10. 模板方法模式(Template Method Pattern)

模板方法模式的本质是:

在父类定义一个操作的算法骨架(模板),而将一些可变的步骤延迟到子类去实现。

简单说:

  • 父类固定流程框架

  • 子类定义具体细节

  • 保证整体流程稳定,但细节可以自由变化。


✏️ 为什么要用模板方法模式?

  • 固定流程标准,防止子类破坏流程结构。

  • 让子类只关注差异化实现,复用公共逻辑。

  • 满足开闭原则,新增业务只需继承,不改动父类。


✏️ Spring / Spring Boot中的应用示例


JdbcTemplate / RedisTemplate / RestTemplate

Spring提供了各种Template类,使用了模板方法模式。

JdbcTemplate为例:

  • 固定了获取连接 -> 执行SQL -> 释放资源的流程。

  • 留出扩展点,比如定义ResultSet如何映射成对象(RowMapper接口)。


典型流程示例(JdbcTemplate简化版)

public class JdbcTemplate {public <T> List<T> query(String sql, RowMapper<T> rowMapper) {// 1. 获取数据库连接// 2. 执行SQL查询// 3. 遍历ResultSet,用RowMapper映射每行数据// 4. 释放连接资源}
}
  • 固定的查询流程由JdbcTemplate控制。

  • 每一行如何映射成对象RowMapper子类控制。


 ✏️手写示例

场景模拟:制作咖啡 or 茶饮品

定义抽象父类,写好模板方法:

public abstract class BeverageTemplate {// 模板方法,定义制作饮品的流程public final void prepareBeverage() {boilWater();brew();pourInCup();addCondiments();}protected void boilWater() {System.out.println("烧水");}protected void pourInCup() {System.out.println("倒入杯中");}// 变化点,留给子类实现protected abstract void brew();protected abstract void addCondiments();
}

定义具体子类(茶):

public class Tea extends BeverageTemplate {@Overrideprotected void brew() {System.out.println("泡茶叶");}@Overrideprotected void addCondiments() {System.out.println("加柠檬");}
}

定义具体子类(咖啡):

public class Coffee extends BeverageTemplate {@Overrideprotected void brew() {System.out.println("冲泡咖啡粉");}@Overrideprotected void addCondiments() {System.out.println("加牛奶和糖");}
}

使用模板方法:

public class Main {public static void main(String[] args) {BeverageTemplate tea = new Tea();tea.prepareBeverage();System.out.println("-----------------");BeverageTemplate coffee = new Coffee();coffee.prepareBeverage();}
}

输出结果:

烧水
泡茶叶
倒入杯中
加柠檬
-----------------
烧水
冲泡咖啡粉
倒入杯中
加牛奶和糖

✅11. 责任链模式(Chain of Responsibility Pattern)

责任链模式的本质是:

将请求沿着一条链进行传递,每个节点可以决定处理还是传递给下一个节点。

简单理解:

  • 多个处理器串成一条链。

  • 一个请求来了,沿着链一个一个传递。

  • 每个处理器只关心自己负责的部分
    处理完了可以继续传递,也可以终止传递


✏️ 为什么要用责任链模式?

  • 发送者处理者解耦,不需要指定由哪个具体对象处理。

  • 灵活组合责任链,可以动态增删节点。

  • 责任细分,每个处理器只做自己的事,符合单一职责原则。

  • 增强扩展性,新增处理器不需要改动已有代码(符合开闭原则)。


✏️ Spring / Spring Boot中的应用示例


(1)Servlet Filter链(FilterChain)

在Java Web开发中:

  • 一个请求经过多个Filter(日志、权限、限流、防护等)处理。

  • 每个Filter处理完后调用 chain.doFilter(request, response),继续往下传。

每个Filter:

  • 处理自己的逻辑。

  • 决定是否继续调用下一个。

这是标准的责任链模式


(2)Spring MVC拦截器链(HandlerInterceptor)

配置多个拦截器组成链

只要在你的WebMvcConfigurer按顺序添加多个拦截器,就自动形成一条链了:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new Interceptor1()).addPathPatterns("/**");   // 拦截所有路径registry.addInterceptor(new Interceptor2()).addPathPatterns("/api/**"); // 拦截/api路径registry.addInterceptor(new Interceptor3()).addPathPatterns("/admin/**"); // 拦截/admin路径}
}

注意:

  • 注册顺序决定了链的执行顺序。addPathPatterns()可以控制每个拦截器生效的路径。

  • 如果某个拦截器的preHandle()返回了false,那么后续的拦截器链不会继续执行,请求也不会进入Controller了。

  • preHandle按注册顺序执行postHandle和afterCompletion按注册顺序的逆序执行

处理+可中断+链式传递,完全符合责任链模式!


 ✏️手写示例

场景模拟:请求处理责任链(日志、鉴权)


定义抽象处理器(Handler):

public abstract class Handler {protected Handler next;// 设置下一个处理器public void setNext(Handler next) {this.next = next;}// 处理请求public abstract void handle(String request);
}

定义具体处理器

日志处理器:

public class LogHandler extends Handler {@Overridepublic void handle(String request) {System.out.println("日志记录:" + request);if (next != null) {next.handle(request);}}
}

鉴权处理器:

public class AuthHandler extends Handler {@Overridepublic void handle(String request) {System.out.println("鉴权检查:" + request);if (next != null) {next.handle(request);}}
}

组装责任链并使用:

public class Main {public static void main(String[] args) {Handler logHandler = new LogHandler();Handler authHandler = new AuthHandler();logHandler.setNext(authHandler); // 先日志,再鉴权logHandler.handle("用户请求访问系统资源");}
}

✅ 12. 观察者模式(Observer Pattern)

观察者模式的本质是:

定义对象之间一对多的依赖关系,当主题对象状态变化时,所有依赖它的观察者都会收到通知并自动更新。

简单理解:

  • 一个主题对象(Subject)。

  • 多个观察者对象(Observer)。

  • 主题变化 → 通知所有观察者。


✏️ 为什么要用观察者模式?

  • 实现发布者与订阅者之间的松耦合

  • 灵活扩展:任意增加/减少观察者,无需改动主题对象。

  • 实时响应:事件驱动,变化自动通知。


✏️ Spring / Spring Boot中的应用示例


Spring事件机制(ApplicationEventPublisher)

在Spring中:

  • 通过 ApplicationEventPublisher 发布事件(比如用户注册、订单完成等)。

  • 有多个 ApplicationListener / @EventListener 注册监听器。

  • 发布者不需要知道谁在监听,监听器只管监听自己感兴趣的事件。

  • 发布事件
    调用 applicationContext.publishEvent(event)
    AbstractApplicationContext.publishEvent()
    getApplicationEventMulticaster().multicastEvent(event)

  • 分派给监听器
    SimpleApplicationEventMulticaster(默认实现)维护一个监听器列表,对每个注册的 ApplicationListener

    • 调用 supportsEventType() 判断是否感兴趣;

    • 若是,则同步或异步执行 listener.onApplicationEvent(event)

  • 监听器注册
    上下文启动时,容器会扫描所有实现 ApplicationListener 接口的 Bean,或带 @EventListener 注解的方法,
    并将它们注册到 ApplicationEventMulticaster

定义事件:

public class OrderCreatedEvent extends ApplicationEvent {private final String orderId;public OrderCreatedEvent(Object source, String orderId) {super(source);this.orderId = orderId;}public String getOrderId() {return orderId;}
}

发布事件:

@Autowired
private ApplicationEventPublisher publisher;public void createOrder(String orderId) {publisher.publishEvent(new OrderCreatedEvent(this, orderId));
}

监听事件:

@Component
public class OrderCreatedListener {@EventListenerpublic void onOrderCreated(OrderCreatedEvent event) {System.out.println("收到订单创建事件:" + event.getOrderId());}
}

一发布,所有监听器同步或异步收到通知。


 ✏️手写示例

场景模拟:消息发布订阅


定义主题(Subject)接口:

public interface Subject {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers(String message);
}

定义观察者(Observer)接口:

public interface Observer {void update(String message);
}

主题实现类:

import java.util.ArrayList;
import java.util.List;public class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String message) {for (Observer observer : observers) {observer.update(message);}}
}

观察者实现类:

public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " 收到消息:" + message);}
}

测试使用:

public class Main {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observerA = new ConcreteObserver("观察者A");Observer observerB = new ConcreteObserver("观察者B");subject.addObserver(observerA);subject.addObserver(observerB);subject.notifyObservers("系统通知:有新活动上线!");}
}

相关文章:

  • deepSeek浅谈对vue的mixin的理解,用于什么应用场景?
  • Vue3 通过Vue3-Print-Nb在线工单打印 模板打印 自定义打印 打印下载
  • 660SJBH企业信息管理系统
  • SPL 量化 复权数据
  • uniapp跨平台开发---动态控制底部切换显示
  • 【WEB3】web3.0是什么
  • Android开发中svg转xml工具使用
  • ‌sd - 批量修改文本文件的命令和软件工具
  • 深入理解编程中的同步与异步:原理、区别及实战应用
  • 基于边缘人工智能的AI无人机-更高效更安全的飞行任务执行
  • 【SpringMVC】概念引入与连接
  • EKS环境下服务重启50X错误
  • 小白学习java第16天(上): javaWeb
  • LLM开发——基于DeepSeek R1 和 Qwen 构建智能检索增强生成系统
  • STM32(M4)入门:定时器延时与系统滴答(价值 3w + 的嵌入式开发指南)
  • Java大厂面试:互联网医疗场景中的Spring Boot与微服务应用
  • 【应用密码学】实验二 分组密码(2)
  • 获取电脑mac地址
  • 特征工程三:数据特征之词干提取器(stemmer)
  • 如何有效防止 SQL 注入攻击?
  • 女乘客遭顺风车甩客、深夜丢高速服务区,滴滴霸道回应:赔五百元
  • 读科学发展的壮丽史诗,也读普通人的传奇
  • 白酒瓶“神似”北京第一高楼被判侵权,法院一审判赔45万并停售
  • 特朗普说克里米亚将留在俄罗斯,泽连斯基:绝不承认
  • 魔都眼丨人形机器人“华山论剑”:拳击赛缺席,足球赛抢镜
  • 人大法工委:涉核领域还需要有一部统领性的基础法律