• 代码可扩展示例:元素构建


    引语

    “代码可扩展的一个小技巧” 一文中谈到,要实现代码可扩展性,需要能够识别变化。

    如何识别变化呢? 有两个症状:

    • 相似模式的代码累积、膨胀;

    • switch 语句,每个分支有相似的代码。

    通过这两点,就能判别出变化所在。现在变化频度越高,将来就更容易变化。


    例子

    下面是另一个例子。

    新入侵检测里,需要存储大量 agent 上报的信息,比如进程树、文件、脚本、webfile、网络连接信息等。 代码如下:

    
    // 进程树
    List<ProcessTreeDTO> processTree = singleDetectionDetail.getProcessTree();
    if (CollectionUtils.isNotEmpty(processTree)) {
        elementDOList.addAll(buildProcessTrees(processTree));
    }
    
    // 文件信息
    List<FileInfoDTO> file = singleDetectionDetail.getFile();
    if (CollectionUtils.isNotEmpty(file)) {
        elementDOList.addAll(buildFileInfos(agentId, file, fhashMap));
    }
    
    // 脚本文件
    List<ScriptDTO> scripts = singleDetectionDetail.getScripts();
    if (CollectionUtils.isNotEmpty(scripts)) {
        elementDOList.addAll(buildScripts(agentId, scripts, fhashMap));
    }
    
    // web文件
    List<WebfileDTO> webfile = singleDetectionDetail.getWebfile();
    if (CollectionUtils.isNotEmpty(webfile)) {
        elementDOList.addAll(buildWebFile(agentId, webfile, fhashMap));
    }
    

    显然,这样累积,这个类会膨胀得很厉害,也容易产生冲突。 如何重构呢?

    通过代码分析,很容易就能知道,这些代码遵循相似的模式: 将一些上报的数据转换成元素对象列表。 据此,就可以定义接口:

    
    /**
     * 元素构建器
     */
    public interface ElementBuilder {
    
        /**
         * 是否必要构建
         * @param context 元素构建上下文语境
         * @return 是否必要构建详情
         */
        boolean need(ElementBuilderContext context);
    
        /**
         * 元素构建器
         * @param context 元素构建上下文语境
         * @return 构建的元素
         */
        List<ElementDO> buildFrom(ElementBuilderContext context);
    
    }
    
    
    

    有童鞋可能会问: 明明参数只要 DTO 对象列表、agentId、fhashMap ,为什么要定义一个 ElementBuilderContext 呢?

    其实,这是最终的结果。在重构的过程中,显然不是一步到位的。比如,我可能最开始只定义了 List buildFrom(LIst dtoList); 随后发现这样不够,必须定义成 List buildFrom(LIst dtoList, String agentId, Map<String, HashDTO> fhashMap); 但这样仍然是不够的。因为很难预想后面还需要什么信息。因此,定义一个 Context 参数对象就是一个常用实践。

    有了这个定义,原有的代码就很容易转换成一个组件类:

    
    
    /**
     * 文件元素构建
     * Created by qinshu on 2022/3/9
     *
     * 源代码由许文进编写,由舒琴重构
     */
    @Component
    public class FileBuilder implements ElementBuilder {
    
        /**
         * 构建文件信息
         */
        @Override
        public List<ElementDO> buildFrom(ElementBuilderContext context) {
           // codes for build elements
        }
    
        @Override
        public boolean need(ElementBuilderContext context) {
            SingleDetectionDetail agentDetectionDetail = context.getDetail();
            return CollectionUtils.isNotEmpty(agentDetectionDetail.getFile());
        }
    

    最终,元素构建流程为:

    
    ElementBuilderContext context = ElementBuilderContext.builder()
            .agentId(agentId)
            .xxx(xxx)
            .build();
    
    // 元素构建
    
    for(ElementBuilder elementBuilder: elementBuilders) {
        if (elementBuilder.need(context)) {
            elementDOList.addAll(elementBuilder.buildFrom(context));
        }
    }
    
    

    后续再需要构建新元素,只要添加实现 ElementBuilder 的子类即可。实现了开闭原则。


  • 相关阅读:
    eclipse导入github项目
    深入理解BFC和Margin Collapse
    前端开发必备!Emmet使用手册
    Backbone.js的技巧和模式
    智能选择器和语义化的CSS
    IE常见BUG总结(持续更新)
    表格元素的完全指南(译)
    display:inline-block;在各浏览器下的问题和终极兼容办法
    float的深入剖析
    javascript正则表达式小技巧
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/15996117.html
Copyright © 2020-2023  润新知