说说设计模式~责任链模式

发布时间 2023-06-28 10:08:22作者: 张占岭

回到目录

责任链模式

它是一种设计模块,主要将操作流程与具体操作解耦,让每个操作都可以设置自己的操作流程,这对于工作流应用是一个不错的选择!
下面是官方标准的定义:责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

使用场景

责任链模式在以下情况下可以被用到:

  1. 多个对象按照特定顺序依次处理请求:当存在多个对象需要依次处理请求,并且每个对象都有可能处理请求或将请求传递给下一个对象时,责任链模式可以很好地组织和管理这些对象。

  2. 需要动态指定处理对象:责任链模式可以通过动态设置责任链的关系,灵活地指定处理对象。可以根据实际情况动态增加、移除或调整处理者的顺序,而不需要修改客户端代码。

  3. 避免请求发送者和接收者之间的耦合关系:使用责任链模式可以将请求发送者和接收者解耦,发送者只需要将请求发送给责任链的第一个处理者,而不需要关心具体是哪个处理者来处理请求。

  4. 处理请求的对象需要进行动态配置:责任链模式可以通过配置文件、数据库等方式来动态配置处理者的顺序和条件,而不需要修改代码。

  5. 请求的处理逻辑具有变化和扩展的可能性:责任链模式可以很方便地对处理逻辑进行扩展和变化。可以通过增加新的处理者来扩展处理逻辑,也可以通过修改现有处理者的条件判断来变化处理逻辑。

一些常见的使用场景包括:

  • 客户端请求的处理:比如Web请求处理、日志记录、安全认证等。
  • 错误处理和异常处理:将异常或错误从一个处理者传递给下一个处理者进行处理,直到找到能够处理它的处理者。
  • 负载均衡:按照一定策略将请求传递给多个服务器进行处理,直到有服务器能够处理请求。
  • 事件驱动系统:通过触发事件并将事件传递给相关的处理者来实现事件的处理和响应。

需要注意的是,责任链模式并不保证一定会有处理者能够处理请求,因此需要在责任链末端进行处理请求无法被处理的情况。

实例中算法说明

  • 每种handler只使用一次
  • 按最高优先级去使用,符合就用,不符合就走下一个策略
  • 具体链条
    • VipHandler >10000
      • BigGiftHandler >1000
        • DiscountHandler >200
          • CouponHandler >100

代码实现

  • 定义处理请求的接口(Handler):
public interface Handler {

	void handleRequest(Order order);

	void setNextHandler(Handler nextHandler);

}
  • 具体处理请求CouponHandler
public class CouponHandler implements Handler {

	private static final Logger logger = LoggerFactory.getLogger(CouponHandler.class);

	private Handler nextHandler;

	@Override
	public void handleRequest(Order order) {
		// 这是可以想用多个责任链的实现,如果是只使用1个,需要加上200的限制,就是每个订单只能现用1种优惠
		if (order.getTotalPrice() >= 100) {
			// 应用优惠券打9折
			order.setTotalPrice(order.getTotalPrice() * .9);
			logger.info("Coupon 0.9 applied to order,{}", order.getOrderId());
		}else if (nextHandler != null) {
				nextHandler.handleRequest(order);
			}
	}

	public void setNextHandler(Handler nextHandler) {
		this.nextHandler = nextHandler;
	}

}
  • 具体处理请求DiscountHandler
 public class DiscountHandler implements Handler {

	private static final Logger logger = LoggerFactory.getLogger(CouponHandler.class);

	private static final double DISCOUNT = .8;

	private Handler nextHandler;

	@Override
	public void handleRequest(Order order) {
		if (order.getTotalPrice() >= 200) {
			// 应用折扣,折扣为标准的8折
			order.setTotalPrice(order.getTotalPrice() * DISCOUNT);
			logger.info("Discount 0.8 applied to order,{}", order.getOrderId());
		}
		else if (nextHandler != null) {
			nextHandler.handleRequest(order);
		}

	}

	public void setNextHandler(Handler nextHandler) {
		this.nextHandler = nextHandler;
	}

}

这个具体命令是可以扩展的,这也是职责链(责任链)的最重要的体现。

  • 命令模式,方便将命令之久,及后期的动态配置
@Data
@AllArgsConstructor
public class HandlerModel implements Comparable<HandlerModel> {

	private String title;

	private String classPath;

	private Integer sort;

	@Override
	public int compareTo(HandlerModel o) {
		return o.getSort() - this.sort; // 降序
	}

}
  • 命令工厂,这里使用了强编码的方式配置命令,真实项目中,这些命令可以配置到数据库中
/**
 * 折扣工厂.
 *
 * @author lind
 * @date 2023/6/28 9:22
 * @since 1.0.0
 */
public class HandlerFactory {

	public static Handler handlerFactory() {
		List<HandlerModel> handlerModels = new ArrayList<>();
		handlerModels.add(
				new HandlerModel("CouponHandler", "com.lind.common.pattern.chinaorder.handler.CouponHandler", 1));
		handlerModels.add(
				new HandlerModel("DiscountHandler", "com.lind.common.pattern.chinaorder.handler.DiscountHandler", 2));
		handlerModels.add(
				new HandlerModel("BigGiftHandler", "com.lind.common.pattern.chinaorder.handler.BigGiftHandler", 3));
		handlerModels.add(
				new HandlerModel("VipHandler", "com.lind.common.pattern.chinaorder.handler.VipHandler", 4));
		return createHandler(handlerModels);
	}

	private static Handler createHandler(List<HandlerModel> handlerModels) {
		Handler handler = null;
		Handler previousHandler = null;

		for (HandlerModel handlerModel : handlerModels.stream().sorted().collect(Collectors.toList())) {
			try {
				Handler currentHandler = (Handler) Class.forName(handlerModel.getClassPath()).newInstance();
				if (previousHandler != null) {
					previousHandler.setNextHandler(currentHandler);
				}
				else {
					handler = currentHandler;
				}
				previousHandler = currentHandler;
			}
			catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
				throw new RuntimeException(e);
			}
		}

		return handler;
	}

}
  • 看一下测试的代码
	public static void main(String[] args) {

		Handler couponHandler = HandlerFactory.handlerFactory();

		Order order1 = new Order("OR01", 150, true);
		couponHandler.handleRequest(order1);
		logger.info("order1:{}\n", order1.getTotalPrice());

		Order order2 = new Order("OR02", 250, true);
		couponHandler.handleRequest(order2);
		logger.info("order2:{}\n", order2.getTotalPrice());

		Order order3 = new Order("OR03", 50, true);
		couponHandler.handleRequest(order3);
		logger.info("order3:{}\n", order3.getTotalPrice());

		Order order4 = new Order("OR04", 5001, true);
		couponHandler.handleRequest(order4);
		logger.info("order4:{}\n", order4.getTotalPrice());

		Order order5 = new Order("OR05", 10001, true);
		couponHandler.handleRequest(order5);
		logger.info("order5:{}\n", order5.getTotalPrice());

待续……
回到目录