使用责任链消除代码中大量的if-else

1 前言

现在有一个文件处理的方法,里面需要判断文档的各种类型、比如img、docx等,然后不同的类型有不同的处理逻辑,大致代码结构如下:

	if (fileName.endsWith(".img")) {
        // todo
        exec();
    } else if (fileName.endsWith(".docx")) {
        // todo
        exec();
    } else if (fileName.endsWith(".txt")) {
        // todo
        exec();
    } else {
        // todo
        exec();
    }

现在有了新的需求,每种类型的文件处理前需要判断文档大小,根据大小做出一些操作,我确实可以在if里面嵌套判断去做,但是考虑到以后的扩展性,以及多人开发时代码的越来越不整洁,打算使用设计模式重构下这部分的代码,以达到规范开发的效果。

经过思考,可以选择策略+map或者责任链模式实现,经过考虑,最终选择了责任链来处理。

很好理解,我的需求是符合条件,则处理,不符合则向下滚动,直到有合适的处理者可以处理。

而在责任链模式里,请求自上而下沿链传递,直到链上的某一个对象决定处理不谋而合。

那开始上代码。

2 简单实现

2.1 责任链接口

public interface IFileInfoHandleChain {

    /**
     * 责任链接口
     * 大文件、image、docx等
     */
    void handleFileInfo(FileInfo fileInfo) throws Exception;

}

2.2 处理者接口

public interface IFileInfoHandler {

    /**
     * 执行真正的逻辑
     */
    void handlerFileInfo(FileInfo fileInfo, IFileInfoHandleChain chain) throws Exception;

}

2.3 抽象处理者类

其实抽象处理类可以按需实现,这里只是整体封装冗余操作,比如一般的责任链节点处理方式:

    @Override
    public void handlerFileInfo(FileInfo fileInfo, IFileInfoHandleChain chain) throws Exception {
		// 满足条件则处理,处理完成后责任链结束
		if (true) {
			// todo
		} 
		//处理不了往下传递
		else {          
		    chain.handlerDocumentInfo(receipt);
		}
	}

很明显这个else块儿内是冗余操作,而且也缺少异常处理,如果当前处理节点异常,则应该向下传递。
创建一个AbstractIFileInfoHandler 类,新增两个抽象方法condition(FileInfo fileInfo)handler(FileInfo fileInfo)
处理者需要继承并实现这两个方法。

public abstract class AbstractIFileInfoHandler implements IFileInfoHandler {

    protected Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 触发条件
     */
    protected abstract Boolean condition(FileInfo fileInfo);

    /**
     * 触发条件后执行的代码
     */
    public abstract void handler(FileInfo fileInfo) throws Exception;

    @Override
    public void handlerFileInfo(FileInfo fileInfo, IFileInfoHandleChain chain) throws Exception {
        if (condition(fileInfo)) {
            try {
                handler(fileInfo);
            } catch (Exception e) {
                log.error(e.getMessage());
                e.printStackTrace();
                chain.handleFileInfo(fileInfo);
            }
        } else {
            chain.handleFileInfo(fileInfo);
        }
    }
}

2.4 处理者的顺序控制

现在我们可以通过继承的方式来创建真正的节点类,比如创建一个DocxFileInfoHandler类:

@Component
public class DocxFileInfoHandler extends AbstractIFileInfoHandler {
    
    @Override
    protected Boolean condition(FileInfo fileInfo) {
        return fileInfo.getName.endsWith("docx");
    }

    @Override
    public void handler(FileInfo fileInfo) throws Exception {
        // todo
    }
}

那么当有多个节点类时,如何控制执行顺序?创建一个注解,只需要在节点类上面添加即可,value越小越靠前处理:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface ChainOrder {

    /**
     * 责任链顺序
     */
    int value() default Integer.MAX_VALUE;
}

使用方式如下:

@Component
@ChainOrder(5)
public class ImageFileInfoHandler extends AbstractIFileInfoHandler {
    
    @Override
    protected Boolean condition(FileInfo fileInfo) {
        return null;
    }

    @Override
    public void handler(FileInfo fileInfo) throws Exception {

    }
}

2.5 容纳处理者的容器

如果是非spring的项目,直接new即可,这里演示的是spring项目,需要使用容器提供的bean。
创建FileInfoHandlerContainer,该类提供所有的处理者

@Component
@Slf4j
public class FileInfoHandlerContainer {

    private FileInfoHandlerContainer() {
    }

    private static ApplicationContext context;

    @Autowired
    public void setApplicationContext(ApplicationContext context) {
        FileInfoHandlerContainer.context = context;
    }

    private static List<IFileInfoHandler> documentTransHandlers = null;

    public static List<IFileInfoHandler> getSingleFileInfoHandlers() {
        if (documentTransHandlers == null) {
            documentTransHandlers = new ArrayList<>();
            Map<IFileInfoHandler, Integer> handlerOrderMap = new HashMap<>();

            final Collection<IFileInfoHandler> handlers = context.getBeansOfType(IFileInfoHandler.class).values();
            for (IFileInfoHandler handler : handlers) {
                for (Annotation annotation : handler.getClass().getAnnotations()) {
                    if (annotation.annotationType().equals(ChainOrder.class)){
                        final ChainOrder order = (ChainOrder) annotation;
                        handlerOrderMap.put(handler, order.value());
                    }
                }
                handlerOrderMap.putIfAbsent(handler, 999);
            }

            List<Map.Entry<IFileInfoHandler, Integer>> sortedHandlers = handlerOrderMap.entrySet()
                    .stream()
                    .sorted(Map.Entry.comparingByValue())
                    .collect(Collectors.toList());

            for (Map.Entry<IFileInfoHandler, Integer> entry : sortedHandlers) {
                documentTransHandlers.add(entry.getKey());
            }
        }
        return documentTransHandlers;
    }

}

2.6 责任链实现

public class IFileInfoHandleChainImpl implements IFileInfoHandleChain {

    //当前处理者位置
    private int index = 0;

    @Override
    public void handleFileInfo(FileInfo fileInfo) throws Exception{
        final List<IFileInfoHandler> handlers = FileInfoHandlerContainer.getSingleFileInfoHandlers();
        if (handlers != null && handlers.size() > 0) {
            if (index != handlers.size()) {
                IFileInfoHandler documentTransHandler = handlers.get(index++);
                documentTransHandler.handlerFileInfo(fileInfo, this);
            }
        }
    }
}

2.7 创建工厂生产责任链类

public class FileInfoHandleChainFactory {

    public static IFileInfoHandleChain create() {
        return new IFileInfoHandleChainImpl();
    }
}

3 简单使用

经过对比,很好的消除了大量的if-else,并且有新需求的时候新增处理节点即可,看起来更优雅了!

    public static void main(String[] args) {
        final IFileInfoHandleChain chain = FileInfoHandleChainFactory.create();
        try {
            chain.handleFileInfo(new FileInfo());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L-960

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值