• 无需debug,通过抽象模型快速梳理代码核心流程


    上一篇我们通过DSM来确定了核心对象并构建了抽象模型。
    本篇是《如何高效阅读源码》专题的第八篇,我们来基于抽象模型来梳理核心流程。

    本节主要内容:

    • 如何通过抽象模型来梳理核心流程

    从类名和注释了解类的作用

    上一篇的最后,我们得到了下面的抽象模型。

     

     

     

    可以看到,最下面的三个类RunnerScheduler、RunnerBuilder和Statement,和其它的类没什么关系,我们可以暂时忽略它们。
    从上面的调用关系和依赖关系,我们可以知道:

    • FrameworkMember是个抽象类

    • 其有两个子类FrameworkField和FrameworkMethod

    • FrameworkMember和TestClass都实现了Annotatable接口

    • TestClass调用了FrameworkField、FrameworkMethod两个类和MemberValueConsumer接口

    线条说明:
    白色虚线箭头
    :关联关系,表现为箭头头部的类作为箭头尾部类的方法参数
    白色实线箭头:组合关系,表现为箭头头部的类作为箭头尾部类的字段
    蓝色实线箭头:继承关系,表现为箭头尾部的类继承了箭头头部的类
    绿色虚线箭头:实现关系,表现为箭头尾部的类实现了箭头头部的接口
    前面的文章中还有两种箭头
    黄色虚线:注解依赖,即一个类使用了某个注解
    红色实现:内部类,即一个类是另一个类的内部类

    我们分别打开这几个类的源码(选中对应的类,按下F4)来阅读类上的注释,通过类名和类上的注释,我们可以了解到:

    • TestClass是「测试Class」的抽象。例如前面的PersonTest,它是PersonTest.class的抽象。

    • FrameworkField是测试类中的属性或影子属性(包装属性)

    • FrameworkMethod是测试类中的方法或影子方法(包装方法)

    • Annotatable只是统一了获取注解的接口

    • MemberValueConsumer用于收集对应的FrameworkMember的值

    影子属性和影子方法是JUnit注释里的说法,我们暂时先这么称呼。结合前面的概念模型,猜测和Rule有关系。

    构建初步流程

    从类的功能,我们可以梳理出一个大概的流程:

    • TestClass对「测试Class」进行抽象

    • 将「测试Class」中的字段封装为FrameworkField

    • 将「测试Class」中的方法封装为FrameworMethod

    • 将field和method执行的结果存到MemberValueConsumer中

    找出关键方法

    从上面的流程,我们可以梳理出一些关键方法:

    • TestClass应该会接收一个Class类型的参数来构建实例。

    • 同时TestClass应该有方法来解析Class里的field和method,并分别构建为FrameworkField和FrameworkMethod

    • TestClass中应该有方法来将field和method的值设置到MemberValueConsumer中

    • FrameworkField应该有方法来获取自身的值

    • FrameworMethod也应该有方法来获取自身的值

    通过IDEA的Structure视图,我们可以很快的定位到对应的方法:

    • TestClass中有一个有参的构造方法,接收Class类型的参数

    • 通过scanAnnotatedMembers方法扫描方法和属性,来构建FrameworkField和FrameworkMethod

    • 注意最后两行,makeDeeplyUnmodifiable方法是干嘛用的呢?看名字是将对象转换为不可变的,为什么要转换成不可变对象呢?

     

     

    转换为不可变对象无非两种情况:

    • 不希望对象被修改,特别是多线程情况下,可能会有不可预期的修改

    • 没有修改,也就可以安心的使用多线程,不用考虑锁的问题。

    不过由于此方法非核心方法,我们就暂时不管了。并不影响流程梳理。此问题可以留到后面再来思考答案。
    我们继续看scanAnnotatedMembers方法:

    • 分别遍历方法和属性,将其加入到对应的Map中

    • 注意这里的MethodSorter,它对方法进行了排序

     

     

    另外可以发现TestClass中有两个方法collectAnnotatedFieldValues和collectAnnotatedMethodValues,从名字就可以了解到,这两个方法是用于获取字段和方法的值,并设置到了MemberValueConsumer中。

     

     

     

     

    至此,我们也就梳理出了核心流程,虽然还有几个疑问,但是没关系,我们后面慢慢来解答。

    总结

    本文阐述了基于抽象模型来梳理核心流程的方法,并通过JUnit来演示具体的梳理核心流程的方法。
    下文将对核心流程绘制流程图图,同时将核心流程图和我们的概念模型及抽象模型进行整合,绘制出一个更完整的执行流程图。

  • 相关阅读:
    【EMC专题】静电放电抗扰度测试
    少儿编程 电子学会图形化编程等级考试Scratch三级真题解析(判断题)2022年6月
    MySQL 慢查询日志 使用方法浅析 日志定位与优化技巧
    怎么移除pdf文件编辑限制,有哪些方法?
    Golang net/http 标准库源码学习
    02HTML功能元素
    2024年第十五届蓝桥杯第三期(校内)模拟赛题解
    【C++内存管理侯捷】---学习笔记(下)malloc/free,loki allocator,other issue
    RuntimeError: “slow_conv2d_cpu“ not implemented for ‘Half‘
    Seata 笔记
  • 原文地址:https://www.cnblogs.com/ivaneye/p/16121045.html