Java设计模式技术干货设计模式

如何用责任链模式优雅的实现数据导入?

2019-04-24  本文已影响103人  苦行孙

责任链模式

标准的责任链模式

基本定义

UML 类图

标准实现方式的 UML 类图

标准模式所涉及到的角色:

优点

缺点

扩展:标准责任链模式,加入责任链的上下文管理对象

基本定义

UML 类图

加入责任链的上下文管理对象的 UML 类图

标准模式所涉及到的角色:

优点

功能链

基本定义

UML 类图

类似于标准的责任链模式的扩展模式

常见场景

实际业务场景

最近工作中来了一个数据导入的需求,需要同时支持 xls, txt, csv 格式的业务数据导入,且不同文件的数据格式不一致,那么如何优雅的实现数据的导入呢?

功能分析

由于这几种格式,数据处理的业务逻辑一致,所以预期需要达到以下的三点:

  1. 将数据的读取、解析、转换和校验 的过程与业务处理流程分离。
  2. 将数据的读取、解析任务抽取出来,针对不同的数据格式进行不同的处理。
  3. 需要能够灵活的组装任务,已此达到将基础功能与业务解耦的目的。

综上分析,决定采用标准责任链的变种模式 —— 功能链

UML 类图

类图

代码实现

由于篇幅有限,仅将关键代码贴出


功能链的上下文管理对象的抽象接口,负责构造处理器链。

public interface HandlerChain<T> {
    /** 执行任务 */
    void execute();

    /** 获取上下文参数 */
    T getContext();

    /** 添加任务 */
    HandlerChain<T> append(Handler handler);

    /** 移除任务 */
    HandlerChain<T> remove(Handler handler);
}

使用单向链表的方式实现上下文管理对象。

public class HandlerChainImpl<T> implements HandlerChain<T> {

    private final List<Handler> handlers = new ArrayList<>();

    /** 控制是否可以重复执行 */
    private boolean cyclic;

    /** 执行索引 */
    private int executeIndex = 0;

    @Getter
    private T context;

    @Override
    public void execute() {
        if (hasNext()) {
            next().doHandler(this);
        } else {
            if (cyclic) {
                executeIndex = 0;
            }
        }
    }

    private boolean hasNext() {
        return executeIndex < handlers.size();
    }

    private Handler next() {
        return handlers.get(executeIndex++);
    }

}

定义抽象的处理器接口。

public interface Handler {
    /**
     * 执行任务
     * @param chain 任务链
     */
    void doTask(HandlerChain chain);
}

通过责任链的特性,优雅的实现了 Excel 文件流的打开与关闭。

public class ExcelReadAndCloseHandler implements Handler {
    @Override
    public void doHandler(HandlerChain chain) {
        ExcelDataContext context = (ExcelDataContext) chain.getContext();

        try (Workbook workbook = readExcel(context, context.getExcelWithBytes())) {
            context.setWorkbook(workbook);

            chain.execute();
        } catch (IOException e) {
            throw new UserDataImportException("导入失败:" + e.getMessage());
        }
    }

Excel 文件的数据读取,大体概述。

public class UserDataWithExcelReadHandler implements Handler {
    @Override
    public void doHandler(HandlerChain chain) {
        UserImportDataContext context = (UserImportDataContext) chain.getContext();

        // 概述,读取所有 sheet 表中的所有数据
        for (int dataRowStartIndex = config.getDataRowStartIndex(); dataRowStartIndex <= sheet.getLastRowNum(); dataRowStartIndex++) {
            Row next = sheet.getRow(dataRowStartIndex);

            dataList.add(buildDataItem(cellHeadCellRow, next));
        }
        context.setDataList(dataList);

        chain.execute();
    }
}

数据导入的业务逻辑代码,大体概述。
注:该处理器为最后一步,为了保证后续能够灵活的添加新的任务,因此继续调用 chain.execute() 保证后续执行

public class DataGenerateHandler implements Handler {
    @Override
    public void doHandler(CustomTaskChain chain) {
        UserImportDataContext context = (UserImportDataContext) chain.getContext();
        List<UserDataImportBean> dataList = context.getDataList();

        dataList.forEach(data -> {
            generateUser(data)
            generateJob(data);
            generateRole(data);
        });

        chain.execute();
    }
}

总结

本文主要介绍了行为模式中的责任链模式,将传统的 if...else...语句,通过责任链模式进行分离,使得原来大块的臃肿代码,能够按照业务逻辑和功能重新组合执行,以此来降低耦合度,并提高代码的可复用性。

优点

缺点

上一篇 下一篇

猜你喜欢

热点阅读