⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7273028474981335081 「半亩方塘立身」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

1 责任链模式介绍

意图: 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

主要解决: 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

何时使用: 在处理消息的时候以过滤很多道。

如何解决: 拦截的类都实现统一接口。

关键代码: Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

应用实例:

1、红楼梦中的”击鼓传花”。

2、JS 中的事件冒泡。

3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。

优点:

1、降低耦合度。它将请求的发送者和接收者解耦。

2、简化了对象。使得对象不需要知道链的结构。

3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

4、增加新的请求处理类很方便。

缺点:

1、不能保证请求一定被接收。

2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。

3、可能不容易观察运行时的特征,有碍于除错

2 业务代码使用的例子

利用spring boot注入及接口实现责任链

首先我们定义一个入参Payment

public class Payment {  
private boolean success;

// 其他参数略....

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}
}

再定义一个接口

public interface PaymentProcessor {  
/**
* 节点处理
*
* @param context
*/
void handle(Payment context);

}

接下来我们定义两个实现类CreditCardProcessor、PayPalProcessor.当我们新增节点或者实现时可以直接实现PaymentProcessor接口。这里采用spring注解@Order来定义执行顺序。

@Order(1)  
@Component
public class CreditCardProcessor implements PaymentProcessor {
@Override
public void handle(Payment context) {
System.out.println("Processed credit card payment.");
}
}


@Order(2)
@Component
public class PayPalProcessor implements PaymentProcessor {
@Override
public void handle(Payment context) {
System.out.println("Processed PayPal payment.");

}
}

最后,我们还需要创建一个支付处理servicePaymentHandleChainService,用于管理这些实现类。·这里采用spring注入list的形式,list顺序为上面实现类@Order的顺序

@Service  
public class PaymentHandleChainService {
@Autowired
private List<PaymentProcessor> paymentProcessors;

public void execute(Payment payment) {
for (PaymentProcessor paymentProcessor : paymentProcessors) {
paymentProcessor.handle(payment);
}
}
}

整体结构如下图所示:

我们写个单元测试:

@RunWith(SpringRunner.class)  
@SpringBootTest(classes = SpringExampleApplication.class)
public class PaymentServiceTest {
@Autowired
private PaymentHandleChainService paymentHandleChainService;

@Test
public void test() {
paymentHandleChainService.execute(new Payment());
}
}

结果如下图所示,符合我们预期:

抽象类实现责任链

另一种方式通过抽象类定义链式,我们还是用上面的例子,这里加个抽象类。

public abstract class AbstractPaymentProcessor {  
/**
* 下一个节点
*/
protected AbstractPaymentProcessor next = null;

public void execute(Payment context) throws Exception {
// 上层未执行成功,不再执行
if (!context.isSuccess()) {
return;
}
// 执行当前阶段
doHandler(context);
// 判断是否还有下个责任链节点,没有的话,说明已经是最后一个节点
if (getNext() != null) {
getNext().execute(context);
}
}

public AbstractPaymentProcessor getNext() {
return next;
}

public void setNext(AbstractPaymentProcessor next) {
this.next = next;
}

public abstract void doHandler(Payment content) throws Exception;

public static class Builder {
private AbstractPaymentProcessor head;
private AbstractPaymentProcessor tail;

public Builder addHandler(AbstractPaymentProcessor handler) {
if (this.head == null) {
this.head = handler;
} else {
this.tail.setNext(handler);
}
this.tail = handler;
return this;
}

public AbstractPaymentProcessor build() {
return this.head;
}
}
}

新定义两个实现类CreditCard2Processor、PayPal2Processor

@Component  
public class CreditCard2Processor extends AbstractPaymentProcessor {

@Override
public void doHandler(Payment content) throws Exception {
System.out.println("Processed credit card payment.");
}
}

@Component
public class PayPal2Processor extends AbstractPaymentProcessor {

@Override
public void doHandler(Payment content) throws Exception {
System.out.println("Processed PayPal payment.");
}
}

这种方式使用起来可以自定义节点,比较灵活。

@Test  
public void test2() throws Exception {
paymentHandleChainService.execute(new Payment());
new AbstractPaymentProcessor.Builder()
.addHandler(creditCard2Processor)
.addHandler(payPal2Processor)
.build().execute(new Payment());
}

整体结构如下:

3 责任链模式与策略模式区别

之前我们讲过如何在业务代码中优雅的使用策略模式[1],下面我们来看一下两者的区别。

责任链模式和策略模式都是常见的行为型设计模式,但它们解决的问题和应用场景有一些不同之处。以下是责任链模式和策略模式的主要区别:

1.问题域不同:

  • 责任链模式(Chain of Responsibility):用于构建一个由多个处理器组成的处理链,每个处理器依次尝试处理请求,直到请求被处理或链上没有处理器能够处理为止。主要用于分离请求发送者和接收者,避免紧耦合的处理方式。
  • 策略模式(Strategy):用于定义一组算法或行为,使它们可以相互替换。主要用于在运行时根据不同的情况选择不同的策略,从而实现不同的行为。

3.关注点不同:

  • 责任链模式:关注的是请求的处理流程,它将多个处理器连接起来形成一个处理链,每个处理器负责处理一部分请求,或者将请求传递给下一个处理器。
  • 策略模式:关注的是算法的选择和替换,它将不同的算法封装成策略对象,然后在运行时根据需要选择合适的策略来执行。

3.调用顺序不同:

  • 责任链模式:请求会依次在处理链上传递,每个处理器决定是否处理该请求或将其传递给下一个处理器。
  • 策略模式:客户端代码选择合适的策略对象,然后直接调用所选策略的方法。

4.目的不同:

  • 责任链模式:主要用于处理请求的分发和处理,可以用于动态地组织和调整处理器的顺序和层次。
  • 策略模式:主要用于实现不同的算法或行为,使客户端代码能够根据需求选择适当的策略来完成任务。
文章目录
  1. 1. 1 责任链模式介绍
  2. 2. 2 业务代码使用的例子
    1. 2.1. 利用spring boot注入及接口实现责任链
    2. 2.2. 抽象类实现责任链
  3. 3. 3 责任链模式与策略模式区别