使用责任链模式动态绑定多实现类实例

摘要

  摘要: 由于业务场景复杂,一个算法需要开发行为变化多端的多个实现类,然后在系统运行时根据不同场景装载不同的类实例。为了使源码具有更好的可扩展性和可重用性,在借鉴前人处理方法的基础上,介绍在Spring Boot项目中,基于责任链模式实现动态匹配相关实现类示例,并调用其中的函数。

前言

  责任链模式(Chain of Responsibility Pattern)定义:责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任,实现请求对象与处理对象之间的解耦。

  在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理此请求,那么它会把此请求传给下一个接收者,依此类推。责任链可能是一条直线、一个环链或者一棵树结构的一部分。

  欲了解更多相关知识点请移步《Spring 动态绑定多实现类实例综述》。

业务场景回顾

  需求描述:定制一个绘图工具,她根据客户端发送的指令可以画出正方形、矩形、圆形和三角形等各种各样的几何图形。例如,当客户端需要绘制三角形的时候,就调用绘制三角形的方法;当需要绘制圆形的时候,就调用绘制圆形的方法。

案例分析

  抽象处理者角色ShapeHandler代码如下:

/**
 * 抽象处理者
 *
 * @author Wiener
 * @date 2021/1/13
 */
public abstract class ShapeHandler {

    public abstract void draw(String code);
    
    // 持有后继责任对象
    protected ShapeHandler next;

    public ShapeHandler getNext() {
        return next;
    }
    public void setNext(ShapeHandler next) {
        this.next = next;
    }
}

  定义两个具体处理者TriangleHandler和CircleHandler:

import org.springframework.stereotype.Service;

/**
 * TODO
 *
 * @author Wiener
 * @date 2021/1/13
 */
@Service
public class TriangleHandler extends ShapeHandler{
    @Override
    public void draw(String code) {
        //判断是否能够处理当前请求
        if ("triangle".equals(code)) {
            System.out.println("Inside TriangleHandler::draw() method.");
        } else {
            //由下一个处理者处理
            getNext().draw(code);
        }
    }
}

// ---我是分割线---

import org.springframework.stereotype.Service;

/**
 * TODO
 *
 * @author Wiener
 * @date 2021/1/13
 */
@Service
public class CircleHandler extends ShapeHandler {
    @Override
    public void draw(String code) {
        if ("circle".equals(code)) {
            System.out.println("Inside CircleHandler::draw() method.");
        } else {
            getNext().draw(code);
        }
    }
}

  这里省略画图工具的其它两个实现类,请读者自行编码。其实,不加也没有关系,两个处理者已经满足我们的测试需求。下面一段代码用于构建一个绘图工具调度中心,其核心是对每个ShapeHandler的子类都绑定下一个需要执行的ShapeHandler子类,从而构造一个完整的链式调用。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 构造调用链
 *
 * @author Wiener
 * @date 2021/1/13
 */
@Component
public class ShapeHandlerChain implements ApplicationContextAware, InitializingBean {

    private ApplicationContext applicationContext;
    private ShapeHandler header;

    public void toDraw(String code) {
        header.draw(code);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, ShapeHandler> beansOfTypeMap = applicationContext.getBeansOfType(ShapeHandler.class);
        if (beansOfTypeMap == null || beansOfTypeMap.size() == 0) {
            return;
        }
        List<ShapeHandler> handlers = beansOfTypeMap.values().stream().collect(Collectors.toList());
        int size = handlers.size();
        for (int i = 0; i < size; i++) {
            ShapeHandler shapeHandler = handlers.get(i);
            if (i != size - 1) {
                shapeHandler.setNext(handlers.get(i + 1));
            }
        }
        header = handlers.get(0);
    }
}

  我们只需要在客户端向函数toDraw(String code)传入约定的入参circle和triangle等即可完成方法调用。如果想为绘图工具类添加新的绘图方法五角星,只需要让五角星类继承超类ShapeHandler,然后重写(Override)draw函数即可,不用修改其它的已有绘图类。

  下面蜻蜓点水般地介绍一下函数getBeansOfType(Class type)。一个类如果由Spring IoC容器管理,则 ApplicationContext的getBeansOfType这个函数就能返回此类的全部子类,实现方便地管理某个类的全部派生类实例;值得注意的是,此函数不返回抽象类。

结束语

  绘图工具类在不同的条件下会使用不同的绘图方法, 本文介绍了使用责任链模式动态绑定画图实例的方法。文章到这里就结束了,看完之后你有什么想法想要跟大家分享呢?评论区在等着你!

Reference


  读后有收获,小礼物走一走,请作者喝咖啡。

赞赏支持

原文地址:https://www.cnblogs.com/east7/p/14390802.html