职责链形式(Chain of Responsibility Pattern)是一种行为型设计形式,它经过将恳求的发送者和接收者解耦,使多个目标都有时机处理恳求。在这个形式中,恳求沿着一个处理链顺次传递,直到有一个目标能够处理它停止。

本文将详细介绍职责链形式的概述、运用场景以及代码示例,来协助读者更好地了解和运用这个形式。

1. 简介

形式概述

职责链形式的核心思想是将恳求的发送者和接收者解耦,使得多个目标都有时机处理恳求。在职责链形式中,恳求会沿着一个处理链顺次传递,每个处理者都有时机处理恳求,假如一个处理者不能处理恳求,则将恳求传递给下一个处理者,直到有一个处理者能够处理它。

职责链形式包含以下几个角色:

设计模式之不一样的责任链模式

  • 抽象处理者(Handler):界说了处理恳求的接口,通常包含一个指向下一个处理者的引用,用于将恳求传递给下一个处理者。
  • 详细处理者(ConcreteHandler):完成了处理恳求的接口,详细处理者能够决议是否处理恳求,假如不能处理,则将恳求传递给下一个处理者。
  • 客户端(Client):创立处理者目标并组成职责链的结构,担任将恳求发送给第一个处理者。

长处与缺点

长处:

  • 职责链形式能够完成恳求的发送者和接收者之间的解耦。发送者只需求将恳求发送给第一个处理者,无需关怀详细是哪个处理者来处理。这样,体系的灵敏性大大增强,能够随时增加或修改处理者的次序。
  • 职责链形式能够避免恳求的发送者和接收者之间的紧耦合。每个处理者只需求关怀自己担任的恳求类型,无需关怀其他恳求。这样,体系的可维护性也得到了提高。
  • 职责链形式能够灵敏地动态增加或删除处理者。咱们能够依据实际情况来调整职责链的结构,以满足不同的事务需求。

缺点:

  • 复杂度会显着提高,假如职责链过长或者处理者之间的联系复杂,或许还会导致性能下降和调试困难。

运用场景

职责链形式在许多不同的运用场景中都有广泛的运用。下面列举了一些常见的运用场景:

  • 恳求处理链:当一个恳求需求经过多个处理过程或处理者进行处理时,能够运用职责链形式。每个处理者担任一部分逻辑,处理完后能够选择将恳求传递给下一个处理者,然后形成一个处理链。
  • 日志记载:在日志体系中,能够运用职责链形式来记载日志。不同的处理者能够担任不同等级的日志记载,例如,一个处理者担任记载过错日志,另一个处理者担任记载调试日志,然后按照链式结构传递日志。
  • 身份验证和权限查看:在身份验证和权限查看体系中,能够运用职责链形式来验证用户的身份和权限。每个处理者能够查看特定的条件,例如用户名和暗码的正确性、账户是否锁定等。假如一个处理者无法经过验证,能够将恳求传递给下一个处理者。
  • 数据过滤和转化:在数据处理过程中,能够运用职责链形式来进行数据过滤和转化。每个处理者能够依据特定的条件过滤数据或对数据进行转化,然后将处理后的数据传递给下一个处理者。
  • 过错处理和反常处理:在过错处理和反常处理体系中,能够运用职责链形式来处理过错和反常。不同的处理者能够处理不同类型的过错或反常,并依据需求将过错或反常传递给下一个处理者进行进一步处理或记载。

2. Java 代码示例

Java 中完成职责链形式有多种办法,包含根据接口、根据抽象类、根据注解等。下面将详细介绍根据接口的常见完成办法。

根据接口的完成办法是经过界说一个处理恳求的接口,每个处理者完成这个接口,并在自己的完成中决议是否处理恳求和传递恳求给下一个处理者。

首要,咱们界说一个处理恳求的接口 Handler 以及恳求入参 Request

public interface Handler {
    void handleRequest(Request request);
}
public class Request {
    private String type;
    // 省略getter、setter
}

然后,咱们创立3个详细的处理者类完成这个接口,在详细处理者类的完成中,首要判断自己是否能够处理恳求,假如能够处理,则进行处理;否则将恳求传递给下一个处理者。代码如下:

public class ConcreteHandlerA implements Handler {
    private Handler successor;
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    public void handleRequest(Request request) {
        if (request.getType().equals("A")) {
            // 处理恳求的逻辑
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
public class ConcreteHandlerB implements Handler {
    private Handler successor;
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    public void handleRequest(Request request) {
        if (request.getType().equals("B")) {
            // 处理恳求的逻辑
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
public class ConcreteHandlerC implements Handler {
    private Handler successor;
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    public void handleRequest(Request request) {
        if (request.getType().equals("C")) {
            // 处理恳求的逻辑
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

接下来,咱们创立一个客户端类 Client,用于创立处理者目标并组成职责链的结构:

public class Client {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();
        handlerA.setSuccessor(handlerB);
        handlerB.setSuccessor(handlerC);
        // 创立恳求并发送给第一个处理者
        Request request = new Request("A");
        handlerA.handleRequest(request);
    }
}

在客户端类中,咱们创立了详细的处理者目标,并经过 setSuccessor() 办法将它们组成一个职责链的结构。然后,创立一个恳求目标,并将恳求发送给第一个处理者。

根据接口的完成办法简单直观,每个处理者只需求完成一个接口即可。可是它的缺点是假如职责链较长,需求创立多个处理者目标,增加了体系的复杂性和资源耗费。下面根据 Spring 结构完成一个高档版的职责链形式。

3. Spring 代码示例

在实际开发中,一个恳求会在多个处理器之间流通,每个处理器都能够处理恳求。

假设咱们有一个 Spring 结构开发的订单处理体系,订单需求顺次经过订单查看、库存处理、付出处理。假如某个处理环节无法处理订单,将会终止处理并返回过错信息,只要每个处理器都完成了恳求处理,这个订单才算法下单成功。

首要,咱们界说一个订单类 Order

@Data
@AllArgsConstructor
public class orderNo {
    private String orderNumber;
    private String paymentMethod;
    private boolean stockAvailability;
    private String shippingAddress;
}

然后,咱们界说一个抽象订单处理者类 OrderHandler

public abstract class OrderHandler {
    public abstract void handleOrder(Order order);
}

接下来,咱们创立详细的订单处理者类继承自抽象订单处理者类,完成相应的办法,并注册到 Spring 中,

@Component
public class CheckOrderHandler extends OrderHandler {
    public void handleOrder(Order order) {
        if (StringUtils.isBlank(order.getOrderNo())) {
            throw new RuntimeException("订单编号不能为空");
        }
        if (order.getPrice().compareTo(BigDecimal.ONE) <= 0) {
            throw new RuntimeException("订单金额不能小于等于0");
        }
        if (StringUtils.isBlank(order.getShippingAddress())) {
            throw new RuntimeException("收货地址不能为空");
        }
        System.out.println("订单参数检验经过");
    }
}
@Component
public class StockHandler extends OrderHandler {
    public void handleOrder(Order order) {
        if (!order.isStockAvailability()) {
            throw new RuntimeException("订单库存缺乏");
        }
        System.out.println("库存扣减成功");
    }
}
@Component
public class AliPaymentHandler extends OrderHandler {
    public void handleOrder(Order order) {
        if (!order.getPaymentMethod().equals("付出宝")) {
            throw new RuntimeException("不支持付出宝以外的付出办法");
        }
        System.out.println("付出宝预下单成功");
    }
}

在详细订单处理者类的完成中,CheckOrderHandler 担任做订单参数查看、StockHandler 担任做库存扣减、AliPaymentHandler 担任做预下单,每个处理者的逻辑都是相互独立各不不搅扰。


最终,咱们创立一个订单生产链条 BuildOrderChain ,用于组成职责链的链条处理结构:

@Component
public class BuildOrderChain {
    @Autowired
    private AliPaymentHandler aliPaymentHandler;
    @Autowired
    private CheckOrderHandler checkOrderHandler;
    @Autowired
    private StockHandler stockHandler;
    List<OrderHandler> list = new ArrayList<>();
    @PostConstruct
    public void init() {
        // 1. 查看订单参数
        list.add(checkOrderHandler);
        // 2. 扣减库存
        list.add(stockHandler);
        // 3. 付出宝预下单
        list.add(aliPaymentHandler);
    }
    public void doFilter(Order order) {
        for (OrderHandler orderHandler : this.list) {
            orderHandler.handleOrder(order);
        }
    }
}

订单生产链条 BuildOrderChain 类中,咱们经过 @PostConstruct 注解下的 init() 初始化办法,将详细的订单处理者按代码次序组成一个职责链的结构。然后经过 doFilter(order) 办法遍历处理者集合顺次处理。

运行代码:

@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class OrderChainTest {
    @Autowired
    private BuildOrderChain buildOrderChain;
    @Test
    public void test() {
        Order order = new Order("123456", "付出宝",
                      true, "长沙", new BigDecimal("100"));
        buildOrderChain.doFilter(order);
    }
}
-------------------------------
订单参数检验经过
库存扣减成功
付出宝预下单成功

能够看到订单顺次经过校验处理器、库存处理器和付出处理器进行处理,直到最终完成整个订单的处理。


在举个比如,假如咱们的订单针对的是虚拟不限库存产品,咱们不需求进行库存扣减,那咱们能够直接新建 VirtualGoodsOrderChain 虚拟产品订单生产链条类,代码如下,

@Component
public class VirtualGoodsOrderChain {
    @Autowired
    private AliPaymentHandler aliPaymentHandler;
    @Autowired
    private CheckOrderHandler checkOrderHandler;
    List<OrderHandler> list = new ArrayList<>();
    @PostConstruct
    public void init() {
        // 1. 查看订单参数
        list.add(checkOrderHandler);
        // 2 付出宝预下单
        list.add(aliPaymentHandler);
    }
    public void doFilter(Order order) {
        for (OrderHandler orderHandler : this.list) {
            orderHandler.handleOrder(order);
        }
    }
}

运行代码:

@Test
public void virtualOrderTest() {
    Order order = new Order("123456", "付出宝", true, "长沙", new BigDecimal("100"));
    virtualGoodsOrderChain.doFilter(order);
}
-------------------------------------------
订单参数检验经过
付出宝预下单成功

4. 总结

总的来说,职责链形式适用于存在多个处理过程、每个处理过程具有独立逻辑或条件、需求灵敏组合和扩展的场景。经过职责链形式,能够将复杂的处理逻辑拆分为多个独立的处理过程,并且能够动态地组合和调整处理过程的次序,然后提高体系的灵敏性和可维护性。希望本文能够协助读者了解和运用职责链形式,提高软件设计和开发的才能。

重视公众号【waynblog】每周分享技能干货、开源项目、实战经验、高效开发工具等,您的重视将是我的更新动力!