无需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来演示具体的梳理核心流程的方法。
下文将对核心流程绘制流程图图,同时将核心流程图和我们的概念模型及抽象模型进行整合,绘制出一个更完整的执行流程图。
无需debug,通过抽象模型快速梳理代码核心流程的更多相关文章
- TinyHTTP代码核心流程
TinyHTTPd是一个超轻量型Http Server,使用C语言开发,全部代码不到600行 研究HTTP服务器,为了更好的造轮子,看了TinyHTTPd代码,对逻辑处理画个简单流程图(不含底层)
- character-RNN模型介绍以及代码解析
RNN是一个很有意思的模型.早在20年前就有学者发现了它强大的时序记忆能力,另外学术界以证实RNN模型属于Turning-Complete,即理论上可以模拟任何函数.但实际运作上,一开始由于vanis ...
- 中文NER的那些事儿1. Bert-Bilstm-CRF基线模型详解&代码实现
这个系列我们来聊聊序列标注中的中文实体识别问题,第一章让我们从当前比较通用的基准模型Bert+Bilstm+CRF说起,看看这个模型已经解决了哪些问题还有哪些问题待解决.以下模型实现和评估脚本,详见 ...
- 动态生成一个设定好特殊样式的Tlabel,快速生成代码
动态生成一个设定好特殊样式的Tlabel,快速生成代码: 1.自己先在可视化界面设定一个Label,像这样: 2.选择label,快捷键ctrl+C 复制,粘贴带代码编辑器去,会生成一段这样的窗体代码 ...
- 利用sublime的snippet功能快速创建代码段
在前端开发中我们经常会输入相同的一些基本代码,例如常用的jquery引用,bootstrap框架,cssreset等等,如果每次使用时在复制粘贴感觉很麻烦,这里介绍一种更为简洁的方法 利用sublim ...
- Visual Studio 内置快速生产代码简写集合
工作之余,整理了一下,Visual Studio 里面的快速生产代码缩写集合,这个拿出来分享想一下,希望对您有所帮助. 文件下载地址:VS内置生产代码缩写集合文档.rar 首字母 简写 生成代码 a ...
- live Templates 活动模板. 配置完之后,就可以快速编码-代码块
配置:live Templates 活动模板. 配置完之后,就可以快速编码-代码块. 输入startflask敲回车: 就会生成代码: 怎么做到的呢? 如下: 注意第七步: 原本不是cha ...
- Emmet快速编写代码
Emmet快速编写代码 ★div → <div></div>, span → <span></span> ★CSS选择器 给标签指定id选择器 di ...
- 前端html、CSS快速编写代码插件-Emmet使用方法技巧详解
前端html.CSS快速编写代码插件-Emmet使用方法技巧详解 Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来 ...
随机推荐
- Numpy库基础___五
Numpy数据存取 •NumPy的随机数函数 a = np.random.rand(1,2,3) print(a) #[[[0.03339719 0.72784732 0.47527802] # [0 ...
- Linux详解 --- 进程管理
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 进程管理一览 接下来的几篇博客,我将主要按照这个思维导图的划分去进行讲解. 管理 在理解什么是进程管理之前,我想我们可以先理解一下什么是管理! 问 ...
- [八省联考2018]制胡窜 (SAM+大讨论)
正着做着实不太好做,正难则反,考虑反着做. 把i,j看成在切割字符串,我们统计有多少对(i,j)会切割所有与\(s_{l,r}\)相同的串.对于在后缀自动机上表示\(s_{l,r}\)的节点x,x的p ...
- 比Tensorflow还强?
大家好,我是章北海 Python是机器学习和深度学习的首选编程语言,但绝不是唯一.训练机器学习/深度学习模型并部署对外提供服务(尤其是通过浏览器)JavaScript 是一个不错的选择,市面上也出现了 ...
- Spring Boot 多模块项目创建与配置 (转)
转载:https://www.cnblogs.com/MaxElephant/p/8205234.html 最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多 ...
- Java 中如何实现序列化,有什么意义?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流 化.可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间. 序列化是为了解决对象流读写操作时可能引发的问题(如果不进 ...
- Thread 类的 sleep()方法和对象的 wait()方法都可以让线 程暂停执行,它们有什么区别?
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程 暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保 持,因此休眠时间结束后会自动恢复(线程回 ...
- 说说for循环的两种写法
for循环 执行多次,条件写在()里,语法形式: 1 2 3 for(计数器变量;条件;计数器增减){ // 将要执行的代码 } 示例: 1 2 3 for (int i = 0; i < 5; ...
- Swing 是线程安全的?
不是,Swing 不是线程安全的.你不能通过任何线程来更新 Swing 组件,如 JTable.JList 或 JPanel,事实上,它们只能通过 GUI 或 AWT 线程来更新. 这就是为什么 Sw ...
- 如何创建spring web 工程
在项目资源管理器右键,New-Spring Starter Proje 设置一些参数 点击Next,然后勾选两个选项