經過類圖,咱們能夠很容易的瞭解代碼架構,理清模塊之間的關係,html
包括繼承(Inheritance),實現(realization),依賴(dependency),組合(Composition), 聚合(Aggregation), 關聯 (Association) 等等。編程
下面就圖中給出的7種關係一一解讀。設計模式
Compostion 是一種 Association 關係,但它更強調兩個類之間總體和局部關係,它暗示兩個類之間有着相同的生命週期,數據結構
好比說圖中的三個1.多線程
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { ... final W mWindow; ... mWindow = new W(this); //互相引用,因此當一個銷燬時,另一個也沒法存在。 }
Realization就是實現,在Java中體現爲implements 一個接口類interface, 在標準的C++中沒有明確的接口概念,但抽象類實際上起着和接口相似的功能,由於C++的Realization能夠體現爲繼承一個抽象類。在Android 的C++代碼中,有一個特殊的抽象類IInterface, 定義了PC接口類的一些基本方法。架構
有接口就會有引用,在UML中一根最普通的單向箭頭便是引用(關聯)關係。它的含義是,某個對象用到了一個其餘對象的接口或屬性。一般,Assocation 經過兩種方式獲取app
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a, int viewVisibility, final DisplayContent displayContent)
mActivityManager = ActivityManagerNative.getDefault();
C++和Java 的接口都只支持進程內的調用。爲了支持專門用於跨進程的接口調用,Android 專門作了一些規定。異步
凡是以IXXXX 定義的接口類都可以支持IPC(固然,進程內也能夠調用IXXXX定義的接口)。ide
當咱們在圖中看到一個IXXX 接口類,咱們即可以認爲這是一個進程的邊界,他的實現端和調用端對象運行在不一樣的進程裏(至少是不一樣的線程)。函數
如上圖中,IWindow的兩端W對象 和 WindowState 對象就用不一樣的顏色來標明它們分屬於不一樣的進程,W運行在應用程序的進程裏,而WinState存在與System Server 進程裏。
聚合表達了兩個類的從屬關係,但和Composition不一樣,他們的生命週期並不同。
一個經典的例子就是工廠和車子,車子是工廠造出來的,工廠倒閉了,車子能夠繼續開,反之亦然。
圖中PolicyManager 和 PhoneWindow就是相似的關係。
就是最多見的繼承關係了。
複雜的繼承關係很難閱讀和記憶,經過UML圖則方便不少,你能夠清楚到看出繼承關係,同時可以理解繼承的設計思想。
好比說圖中右上角,PhoneWindow 繼承了Window 類,Activity 引用的是其基類Window的對象,但背後真正幹事的是PhoneWindow對象, 由於Acitivy 用的Window類對象是PolicyManager構造出來的。經過這種方式,PhoneWindow的實現細節被PolicyManager 和 Window 基類隱藏起來,從而大大下降了應用程序(Activity) 改變的概率。
這個正是設計模式裏有名的工廠模式之一。
依賴不一樣於引用,依賴者和被依賴着之間沒有直接的對象引用,一般是常量或靜態方法的使用。
好比圖中,Activity使用了PolicyManager類的靜態方法 makeNewWindow() 建立了PhoneWindow對象,咱們說Acitivy 依賴PolicyManager 這個模塊,但它並無引用PoclicyManager的對象。
依賴一般用一根單向虛線箭頭表示。
經過時序圖,咱們能夠了解代碼的調用流程, 並能夠檢查調用過程當中可能產成的潛在問題,如死鎖等。
時序圖能夠從兩個方向去看,縱向和橫向。
縱向描述了一個對象在時間軸上所作的事情,一個方塊經過表明一個函數的調用。
橫向則描述了各個對象之間的調用關係, 包括同步調用,異步調用,返回等等。
此外,在時序圖中,咱們能夠給執行塊賦予不一樣的顏色,表明了他們分別運行在不一樣的進程或線程裏。
下面就是一張時序圖的例子,它描述了Android中一個System server 進程啓動的過程, 圖中的粉紅色註釋列舉了從圖中咱們能夠獲知的一些信息。
這是一個很簡單的例子,圖中有兩個線程,綠色是app線程,它經過調用MediaPlayer 對象的函數來控制播放器,這裏它作了兩件事,Start() 而後 Stop (). 而粉色部分表明Driver 線程,它經過回調函數告知Mediaplayer 一下底層的事件。也就是說Mediaplayer 是一個被兩個線程同時引用的對象,是一個共享的資源。
想固然的,咱們用了一把鎖來保護它,防止他被同時使用產生衝突。因此,圖中,綠色的app在Stop()時候首先拿到了鎖。這時問題發生了,Stop()的過程可能會比較長,中途來了一個事件, 圖中黃色註釋的右方顯示了這個狀況,兩個顏色的長條重疊在一塊兒。這代表有資源衝突發生,也意味着潛在的死鎖風險。咱們假設Stop()的最終目的就是要析構VideoDecoder 對象,但此時,VideoDecoder調用的eventHandler() 在另一個線程還沒返回,理所固然的咱們須要等待它。不幸的是,這個時候死鎖發生了,如圖中紅色註釋所示。
經過簡單的畫這麼一個圖,能夠很輕易的分析出一個死鎖的狀況。那怎麼解決它的,盡能夠的避免圖中不一樣顏色的條塊重疊在一塊兒。看看下面的解決方案
這下贊成了吧,時序圖對分析多線程的編程分析有很大的幫助。咱們應該在設計階段儘量的用類圖和時序圖來幫助咱們避免一些常見的問題,幫助咱們得出一個儘量好的設計。
工具!必須依賴工具,市面上有太多的UML工具,你只須要找一款支持逆向工程的,即將代碼轉換成UML的數據結構,而後將類圖或時序圖一步步的繪製出來。