实现代码可扩展的另一个示例(代码片段)

编程大观园 编程大观园     2022-10-20     778

关键词:

如何识别变化呢? 相似模式的代码累积、膨胀。

引语

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

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

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

  • 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 的子类即可。实现了开闭原则。


实现可扩展代码的四步曲(代码片段)

实现代码可扩展的基本设计原则是开闭原则,即对扩展开放、对修改关闭。要做到这一点,需要经过四步:识别变化、抽离共性和定义接口、实现子类、注入实现和处理框架。可扩展性可扩展性指系统为了应对将来需求变化而提... 查看详情

java示例代码_设计一个没有JavaScript的可扩展HTML表单

java示例代码_设计一个没有JavaScript的可扩展HTML表单 查看详情

java示例代码_在其中一个适配器函数中重新绘制可扩展列表

java示例代码_在其中一个适配器函数中重新绘制可扩展列表 查看详情

java通用配置扩展示例(代码片段)

Java通用配置(一)设计(二)JVM和环境变量实现(三)用户配置实现(四)版本配置实现(五)集成Spring(六)扩展示例本系列参考实现:https://gitee.com/mybatis-mapper/config 查看详情

java通用配置扩展示例(代码片段)

Java通用配置(一)设计(二)JVM和环境变量实现(三)用户配置实现(四)版本配置实现(五)集成Spring(六)扩展示例本系列参考实现:https://gitee.com/mybatis-mapper/config 查看详情

hangfire源码解析-如何实现可扩展ioc的?(代码片段)

...oundjobs.根据上述说明可以简单理解为继承“JobActivator”来实现自定义IOC容器。二、JobActivator//抽象Job生命周期publicabstractclassJobActivatorScope:IDisposable....省略//定义抽象方法,获取实例publicabstractobjectResolve(Typetype);//定义虚方法,摧毁... 查看详情

java示例代码_如何实现OOP,从一个类调用一个实例方法,并将其存储在另一个类的另一个实例方法的数组中

java示例代码_如何实现OOP,从一个类调用一个实例方法,并将其存储在另一个类的另一个实例方法的数组中 查看详情

java示例代码_当一个类也扩展了另一个类时,使其扩展为可观察的

java示例代码_当一个类也扩展了另一个类时,使其扩展为可观察的 查看详情

juc线程池扩展可回调的future(代码片段)

JUC线程池扩展可回调的Future引言简单分析Future的实现原理Future的实现扩展可回调的Future编码实现测试小结引言最近在看JUC线程池java.util.concurrent.ThreadPoolExecutor的源码实现,其中了解到java.util.concurrent.Future的实现原理。从目前j... 查看详情

设计模式工厂方法模式(简介|适用场景|优缺点|代码示例)(代码片段)

...优缺点四、工厂方法模式代码示例1、产品抽象类2、产品实现类13、产品实现类24、抽象工厂类5、实现工厂类16、实现工厂类27、测试类五、扩展上述工厂方法模式1、扩展的产品实现类2、扩展的工厂实现类3、测试类一、工厂方法... 查看详情

一个可扩展的弹幕播放器的html5实现范例---abplayerhtml5(代码片段)

...BPlayer,同时也希望能为新一代的HTML5弹幕播放器打造一个实现范例。这个播放器將用相对通俗易懂的方法,实现最基础的弹幕播放器功能,以供开发者参照。在你的应用中加入ABPlayerHTML5请在 head 元素内引入如下的库。<... 查看详情

zabbix+tidb:可实现水平扩展(代码片段)

什么是tidbTiDB是开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理的融合型分布式数据库产品。具备水平扩容或者缩容、金融级高可用、实时HTAP、云原生的分布式数据库、兼容MySQL5.7协议和MySQL生态等重... 查看详情

es6丨数组的扩展(代码片段)

一、扩展运算符(...)1、数组复制(不是新数组)consta1=[4,5,6,7]consta2=a1a2[0]=666console.log(‘a1‘,a1)//[666,5,6,7]上面的示例,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。a2并不是a1的克隆,而是指向同一份数据的... 查看详情

kotlinexpandablelistview可扩展二级列表(代码片段)

1.Kotlin实现可扩展二级列表效果如下2.activity_list.xml,布局代码如下:......<androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/mRecyclerView"android:layout_width="match_ 查看详情

java示例代码_让可扩展列表的子项可点击,然后做一些事情

java示例代码_让可扩展列表的子项可点击,然后做一些事情 查看详情

从零开始创建一个php扩展(代码片段)

创建一个扩展的基本步骤都有哪些。示例中,我们将实现如下功能:<?phpechosay();?>输出内容:$php./test.php$helloword在扩展中实现一个say方法,调用say方法后,输出helloword。第一步:生成代码PHP为我们提供了生成基本代码的工具e... 查看详情

java示例代码_从Java中的另一个类获取变量

java示例代码_从Java中的另一个类获取变量 查看详情

java示例代码_从类中的另一个函数正确访问方法

java示例代码_从类中的另一个函数正确访问方法 查看详情