责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止,属于行为型模式。就像一场足球比赛,通过层层传递,最终射门。
责任链模式的应用场景
设计模式只是帮助减少代码的复杂性,让其满足开闭原则,提高代码的扩展性。如果不使用同样可以完成需求。
假设业务场景是这样的,我们 系统处在一个下游服务,因为业务需求,系统中所使用的 基础数据需要从上游中台同步到系统数据库
基础数据包含了很多类型数据,虽然数据在中台会有一定验证,但是 数据只要是人为录入就极可能存在问题,遵从对上游系统不信任原则,需要对数据接收时进行一系列校验
最初是要进行一系列验证原则才能入库的,后来因为工期问题只放了一套非空验证,趁着春节期间时间还算宽裕,把这套验证规则骨架放进去
从我们系统的接入数据规则而言,个人觉得需要支持以下几套规则
如果不使用责任链模式,上面说的真实同步场景面临两个问题
综上所述,在合适的场景运用适合的设计模式,能够让代码设计复杂性降低,变得更为健壮。朝更远的说也能让自己的编码设计能力有所提高。
优点
缺点
《Java面试+学习》全家桶合集录
抽象接口RequestHandler
public interface RequestHandler {
void doHandler(String req);
}
抽象类BaseRequestHandler
public abstract class BaseRequestHandler implements RequestHandler {
protected RequestHandler next;
public void next(RequestHandler next) {
this.next = next;
}
}
具体处理类AHandler
public class AHandler extends BaseRequestHandler {
@Override
public void doHandler(String req) {
// 处理自己的业务逻辑
System.out.println("A中处理自己的逻辑");
// 传递给下个类(若链路中还有下个处理类)
if (next != null) {
next.doHandler(req);
}
}
}
当然还有具体的处理类B、C等等,这里不展开赘述。 使用类Client
public class Client {
public static void main(String[] args) {
BaseRequestHandler a = new AHandler();
BaseRequestHandler b = new BHandler();
BaseRequestHandler c = new CHandler();
a.next(b);
b.next(c);
a.doHandler("链路待处理的数据");
}
}
金融业务其中就有一个业务场景:一笔订单进来,会先在后台通过初审人员进行审批,初审不通过,订单流程结束。初审通过以后,会转给终审人员进行审批,不通过,流程结束;通过,流转到下个业务场景。 对于这块业务代码,一套if-else干到底。后来,技术老大CodeReview,点名要求改掉这块。(当然,比较复杂的情况,还是可以用工作流来处理这个场景)。
有的公司业务会调用我们接口,将数据同步过来。同样,我们需要将处理好的数据,传给他们。由于双方传输数据都是加密传输,所以在接受他们数据之前,需要对数据进行解密,验签,参数校验等操作。同样,我们给他们传数据也需要进行加签,加密操作。
对于场景二,我们结合代码一起探讨一下。 1、一切从注解开始,我这里自定义了一个注解@Duty,这个注解有spring的@Component注解,也就是标记了这个自定义注解的类,都是交给spring的bean容器去管理。 注解中,有两个属性:1.type,定义相同的type类型的bean,会被放到一个责任链集合中。2.order,同一个责任链集合中,bean的排序,数值越小,会放到链路最先的位置,优先处理。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Service
public @interface Duty {
/**
* 标记具体业务场景
* @return
*/
String type() default "";
/**
* 排序:数值越小,排序越前
* @return
*/
int order() default 0;
}
2、定义一个顶层的抽象接口IHandler,传入2个泛型参数,供后续自定义。