项目优雅的实现责任链模式

2023-11-01 14:58:23 浏览数 (2)

项目优雅的实现责任链模式

1、创建抽象业务责任链组件

代码语言:javascript复制
/**
 * 抽象业务责任链组件
 * @author zang 
 * @date 2022/10/31 22:46
 */
public interface AbstractChainHandler<T> extends Ordered {

    /**
     * 执行责任链逻辑
     *
     * @param requestParam 责任链执行入参
     */
    void handler(T requestParam);

    /**
     * @return 责任链组件标识
     */
    String mark();
}

上边的代码,是责任链模式中最顶级的解开 handler 方法,其他组件继承这个接口,然后实现 handler 方法,当作具体的实现 mark() 方法,是每个组件的标识,用于标识当前执行的某个过滤器链 这个会在某个过滤器链的顶级接口中设置

2、创建抽象责任链上下文

代码语言:javascript复制

/**
 * 抽象责任链上下文
 *
 * @author zang
 * @date 2022/10/31 20:01
 */
public final class AbstractChainContext<T> implements CommandLineRunner {

    private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();

    /**
     * 责任链组件执行
     *
     * @param mark         责任链组件标识
     * @param requestParam 请求参数
     */
    public void handler(String mark, T requestParam) {
        List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
        if (CollectionUtils.isEmpty(abstractChainHandlers)) {
            throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
        }
        abstractChainHandlers.forEach(each -> each.handler(requestParam));
    }

    /**
     * 在SpringBoot启动时,将所有的责任链组件排好顺序注册到容器中
     * 
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) throws Exception {
        Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder
                .getBeansOfType(AbstractChainHandler.class);
        chainFilterMap.forEach((beanName, bean) -> {
            List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark());
            if (CollectionUtils.isEmpty(abstractChainHandlers)) {
                abstractChainHandlers = new ArrayList<>();
            }
            abstractChainHandlers.add(bean);
            List<AbstractChainHandler> actualAbstractChainHandlers = abstractChainHandlers.stream()
                    .sorted(Comparator.comparing(Ordered::getOrder))
                    .collect(Collectors.toList());
            abstractChainHandlerContainer.put(bean.mark(), actualAbstractChainHandlers);
        });
    }
}

3、具体实现

1、 过滤器链中的顶级接口
代码语言:javascript复制
/**
 * 用户注册责任链过滤器
 *
 */
public interface UserRegisterCreateChainFilter<T extends UserRegisterReqDTO> extends AbstractChainHandler<UserRegisterReqDTO> {

    @Override
    default String mark() {
        return UserChainMarkEnum.USER_REGISTER_FILTER.name();
    }
}
2、具体实现
代码语言:javascript复制
/**
 * 用户注册参数必填检验
 *
 */
@Component
public final class UserRegisterParamNotNullChainHandler implements UserRegisterCreateChainFilter<UserRegisterReqDTO> {

    @Override
    public void handler(UserRegisterReqDTO requestParam) {
        Map<Function<UserRegisterReqDTO, Object>, UserRegisterErrorCodeEnum> fieldCheckMap = new HashMap<>();
        fieldCheckMap.put(UserRegisterReqDTO::getUsername, UserRegisterErrorCodeEnum.USER_NAME_NOTNULL);
        fieldCheckMap.put(UserRegisterReqDTO::getPassword, UserRegisterErrorCodeEnum.PASSWORD_NOTNULL);
        fieldCheckMap.put(UserRegisterReqDTO::getPhone, UserRegisterErrorCodeEnum.PHONE_NOTNULL);
        fieldCheckMap.put(UserRegisterReqDTO::getIdType, UserRegisterErrorCodeEnum.ID_TYPE_NOTNULL);
        fieldCheckMap.put(UserRegisterReqDTO::getIdCard, UserRegisterErrorCodeEnum.ID_CARD_NOTNULL);
        fieldCheckMap.put(UserRegisterReqDTO::getMail, UserRegisterErrorCodeEnum.MAIL_NOTNULL);
        fieldCheckMap.put(UserRegisterReqDTO::getRealName, UserRegisterErrorCodeEnum.REAL_NAME_NOTNULL);

        fieldCheckMap.forEach((fieldGetter, errorCode) -> {
            Object fieldValue = fieldGetter.apply(requestParam);
            if (Objects.isNull(fieldValue)) {
                throw new ClientException(errorCode);
            }
        });
    }

    /**
     * 用户返回当前的的过滤器节点在当前责任链中的优先级
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

我们在使用的时候只需要在业务层,将抽象责任链上下文注入,然后执行handler() 方法将当前责任链的具体实现命传入就可以, 例如handler(UserChainMarkEnum.USER_REGISTER_FILTER.name(), requestParam);

3、后续扩展

后续如果需要增加责任链节点只需要实现对应的责任链顶级接口就可以了 后续如果需要增加新的责任链,只需要创建一个当前责任链顶级接口,继承 AbstractChainHandler 然后去做具体业务实现就可以了

0 人点赞