如有引用參考請詳註出處,感謝
這是資料結構 Array 單向鏈結 的一種應用,串連多個物件,使其都有機會處理請求
如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 DevTech Ascendancy Hub
多個物件 1. 有順序的處理、2. 同一請求
具體要由哪個物件處理可由 運行時動態決定
責任鏈有兩種類型,如下表
責任鏈類型 | 說明 |
---|---|
純 - 責任鏈 | 需求可被責任鏈消費 |
不純 - 責任鏈 | 責任鏈不能處理需求 |
Chain 定義
多個物件都有機會處理請求,避免請求者(request
)、接收處理者(handle
)耦合;將對象鏈成一條鏈,並沿著鏈傳遞直到有處理者
Chain UML 有分為兩種:分別都有兩個行為 請求、處理
合併 請求、處理:這裡我們主要是關注 Linked 的處理
類別 | 功能 |
---|---|
LinkedItem (鏈、抽象) | 其內部有 0 ~ 1 個 LinkedItem,判斷是否讓下一個 LinkedItem 處理;這裡 有 2 個選擇,不是 處理,就是 往下傳遞 |
ConcreateA、B (實作) | 處理使用者的請求 (請求、處理一起) |
LinkedItem 有三個責任
對外開放一個請求處理入口( handleRequest
)
設定鏈的方式 (setNext
)
具體的請求者的抽象方法
抽象定義能處理的級別
抽象定義每個子類處理的方式
分離 請求、處理:我們在基礎的責任鏈上將 請求
、處理
分開
請求
、處理
抽象化類別 | 功能 |
---|---|
LinkedItem (鏈、抽象) | 其內部有 0~1 個 LinkedItem,判斷是否讓下一個 LinkedItem 處理;這裡 有 2 個選擇,不是 1.處理,就是 2.往下傳遞 |
ConcreateLinkedA、B(實作) | 處理使用者的請求 |
Request (抽象) | 抽象化共同處理的請求 |
ConcreateRequestA、B(實作) | 定義請求的詳細規則 |
Chain 設計優點
自由的決定要由何處開始處理這個任務
符合單一職責:一個類只負責它自身要處理的有範圍的邏輯
符合迪米特原則:不用知道別的類如何處理,只須關注自己的部份,其他交給父類處理
請求者(Request)與 處理者(Handler)解偶
處理者不用知道請求的全貌,只須關注部份(關注自己能不能處理、處理方式)
請求者也無須知道是哪個類處理的,只須關注結果即可
Chain 設計缺點
搜尋速度較慢(如 Linked List 的特性)
可以 在
setNext
時設置一個閥值,避免無意識的破壞調系統性能(不好查)
採用遞歸方式運作,也就導致了複雜度增加、可讀性降低
現在假設在申報出國出差的經費,經費需要經過不同主管批省
批省要有順序
每個主管的額度也不相同
LinkedItem (抽象):1. 定義相同行為,並且內部有 2. 0 ~ 1
個相同的抽象成員 (指向 next 處理對象)
handle
方法)ConstractA、B:定義實體處理的子類,並在這裡 由各個子類自行判斷是否處理,在這裡返回的 結果將會決定 Linked 是否繼續往下執行
User 使用:使用者可以自行串接處理的順序,並決定啟動時機
final 關鍵字:
使用 Java 類加載的特性,定義 final 變量 最慢
必須在建構函數中定義
–實作–
Request:定義新增的 Request 抽象類
ConcreateRequestA、B:定義具體的 Request 處理細節
LinkedItem 抽象:也就是處理類的抽象,主要修改接收參數,讓 LinkedItem 抽象
參數依賴抽象 Request
ConcreateLinkedA、B:具體實現抽象 Linked 細節,同上個範例,沒有做修改
User 使用:這裡較不一樣的是使用者必須自訂 Request 需求
這裡可以注意到一點,使用者(高層模塊)通常會使用類一個封裝過得類來進行請求,而不是自己串接任務鏈
可以使用創建類型:像是
Factory
、Builder
設計都可以
–實作–
Android View 的傳遞事件就是使用 Linked 模式,可以參考另一篇 View 事件分發
透過 dispatchTouchEvent 方法來迭代
這裡我們直接從 ViewGroup 接收的 dispatchTouchEvent
方法開始分析
簡單來說,都是傳遞的事件會從 PhoneWindow 的 DecorView (ViewGroup) 往下傳遞事件,傳遞方式是使用 遞迴呼叫 (DFS)
清理當前 View 的事件:如果是 ACTION_DOWN
事件,代表它是一個新的事件,需要清理當前 ViewGroup 的一些設定
關注變數 | 當前數值 |
---|---|
actionMasked | MotionEvent.ACTION_DOWN |
cancelAndClearTouchTargets 方法:透過 TouchTarget Linked 將 cancel 事件傳遞給所有 view
resetTouchState 方法:清除 FLAG_DISALLOW_INTERCEPT
FLAG:不同意 ViewGroup 中斷
檢查該 ViewGroup 中斷事件
關注變數 | 當前數值 |
---|---|
actionMasked | MotionEvent.ACTION_DOWN |
mFirstTouchTarget | null |
檢查事件是否被取消
ViewGroup 處理、分發事件(事件沒有被取消或中斷):在這一步會透過遞迴呼叫,嘗試找到處理事件的 View
這裡的遞迴操作,就是遍歷二元樹的操作
關注變數 | 當前數值 |
---|---|
actionMasked | MotionEvent.ACTION_DOWN |
mFirstTouchTarget | null |
canceled | false |
intercepted | false |
判斷事件是否已經分發到目標 ChildView,1. 如果沒有 ChildView 處理,則拋回到 ViewGroup 的 View、2. 處理 cancel 事件
關注變數 | 當前數值 |
---|---|
actionMasked | MotionEvent.ACTION_DOWN |
mFirstTouchTarget | 有可能為 null (如果是 ChildView 處理就不是 null) |
canceled | false |
intercepted | false |
上面介紹了 ViewGroup 的事件分法,現在介紹 ViewGroup 的事件傳遞 (+Transformed)
處理 View 的取消事件:如果有就透過 dispatchTouchEvent
方法分發給目標 View
計算將被傳遞的 pointer 數量
觸摸數量相同:計算偏移量,再透過 dispatchTouchEvent
方法分發事件給 ChildView
偏移量
如果有調用 scrollTo
or scrollBy
對 ChildView 進行滾動,就會產生 xy 的偏移量
觸摸數量不相同:同上,最終都是透過 dispatchTouchEvent
方法分發事件
物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!
創建模式 - Creation Patterns
:
創建模式用於「物件的創建」,它關注於如何更靈活、更有效地創建對象。這些模式可以隱藏創建對象的細節,並提供創建對象的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結
行為模式 - Behavioral Patterns
:
行為模式關注物件之間的「通信」和「職責分配」。它們描述了一系列對象如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結
結構模式 - Structural Patterns
:
結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結
Java 設計模式
基礎進階