如何在业务代码中优雅的使用责任链模式

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

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

责任链模式介绍

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

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

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

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

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

应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。

优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错

业务代码使用的例子

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

首先我们定义一个入参Payment

java 复制代码
public class Payment {  
    private boolean success;  
    
    // 其他参数略....

    public boolean isSuccess() {  
        return success;  
    }  

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

再定义一个接口

java 复制代码
public interface PaymentProcessor {  
    /**  
    * 节点处理  
    *  
    * @param context  
    */  
    void handle(Payment context);  
  
}

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

java 复制代码
@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的顺序

java 复制代码
@Service  
public class PaymentHandleChainService {  
    @Autowired  
    private List<PaymentProcessor> paymentProcessors;  

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

整体结构如下图所示:

我们写个单元测试:

Java 复制代码
@RunWith(SpringRunner.class)  
@SpringBootTest(classes = SpringExampleApplication.class)  
public class PaymentServiceTest {  
    @Autowired  
    private PaymentHandleChainService paymentHandleChainService;  

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

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

抽象类实现责任链

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

java 复制代码
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;  
        }  
    }  
}

新定义两个实现类CreditCard2ProcessorPayPal2Processor

java 复制代码
@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.");  
    }  
}

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

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

整体结构如下:

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

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

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

  1. 问题域不同:

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

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

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

    • 责任链模式:主要用于处理请求的分发和处理,可以用于动态地组织和调整处理器的顺序和层次。
    • 策略模式:主要用于实现不同的算法或行为,使客户端代码能够根据需求选择适当的策略来完成任务。
相关推荐
oak隔壁找我1 分钟前
MyBatis的MapperFactoryBean详解
后端
王道长AWS_服务器2 分钟前
AWS Elastic Load Balancing(ELB)—— 多站点负载均衡的正确打开方式
后端·程序员·aws
咖啡Beans5 分钟前
SpringBoot2.7集成Swagger3.0
java·swagger
oak隔壁找我8 分钟前
Spring BeanFactory 和 FactoryBean 详解
后端
用户4099322502128 分钟前
只给表子集建索引?用函数结果建索引?PostgreSQL这俩操作凭啥能省空间又加速?
后端·ai编程·trae
oak隔壁找我9 分钟前
SpringMVC 教程
后端
用户34325962788169 分钟前
Spring AI Alibaba中使用Redis Vector报错修改过程
后端
oak隔壁找我9 分钟前
MyBatis和SpringBoot集成的原理详解
后端
聪明的笨猪猪10 分钟前
Java JVM “垃圾回收(GC)”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
oak隔壁找我10 分钟前
SpringBoot @Import 注解详解
后端