無需debug,通過抽象模型快速梳理程式碼核心流程

一瑜一琂發表於2022-04-09

上一篇我們通過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來演示具體的梳理核心流程的方法。
下文將對核心流程繪製流程圖圖,同時將核心流程圖和我們的概念模型及抽象模型進行整合,繪製出一個更完整的執行流程圖。

相關文章