1. 程式人生 > >java設計模式之責任鏈模式、狀態模式、策略模式

java設計模式之責任鏈模式、狀態模式、策略模式

若您對我的分享感興趣可以訪問:java設計模式專欄

在常用的23中設計模式中,有三種模式容易混淆,這三種模式分別是:責任鏈模式、狀態模式以及策略模式

因此接下來我們把這三種模式放在一起討論

1、責任鏈模式(okHttp)
職責鏈的本質是:不同的類對同一個問題的反應
    責任鏈模式下處理者所處的位置決定了其功能,在這裡,最後一個 Interceptor 一定是負責和伺服器實際通訊的,重定向、快取等一定是在實際通訊之前的
責任鏈實現的關鍵有:
(1)需要責任鏈上一系列的處理類實現統一的介面
(2)需要有管理器來指定所有處理類的攔截處理順序
(3)每一個責任鏈上的處理對類都明確自己可以處理的命令,也知道如何將自己不能處理的命令傳遞給該鏈中的下一個處理物件
(4)該模式還描述了往該處理鏈的末尾新增新的處理物件的方法

例如:
OkHttp的網路請求攔截處理鏈就很好的實現了責任鏈的模式
責任鏈模式在 Interceptor 鏈條中得到了很好的實踐,所有的攔截器都實現了統一的介面,請求在多個肩負不同功能的攔截器組成的鏈條中進行傳遞,每個攔截器都有機會處理請求。具體哪個攔截器處理請求需要由執行時刻自動確定
對於把 Request 變成 Response 這件事來說,每個 Interceptor 都可能完成這件事,所以我們循著鏈條讓每個 Interceptor 自行決定能否完成任務以及怎麼完成任務(自力更生或者交給下一個 Interceptor)這樣一來,完成網路請求這件事就徹底從 RealCall 類中剝離了出來,簡化了各自的責任和邏輯

責任鏈模式在安卓系統中也有比較典型的實踐,例如 view 系統對點選事件(TouchEvent)的處理

2、狀態模式

狀態模式目的or意圖:

    控制一個物件內部的狀態轉換的條件表示式過於複雜時的情況,且客戶端呼叫之前不需要了解具體狀態。它把狀態的判斷邏輯轉到表現不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化

其本質是:一個類對不同狀態的多種不同響應

關鍵:

狀態模式是讓各個狀態物件自己知道其下一個處理的物件是誰!即在狀態子類編譯時在程式碼上就設定好了!

https://www.cnblogs.com/kubixuesheng/p/5180509.html

狀態模式和責任鏈模式的比較:

    區別在於狀態模式需要各個狀態類(類比責任鏈上的各個職責類),明確知道自己的下一個需要轉移的狀態是什麼,而責任鏈模式裡的責任類不需要知道自己的下一個需要轉移的職責是哪個,等價於——發出完成某任務請求的客戶端並不知道鏈上的哪一個物件最終處理這個請求,這個組裝過程需要交給環境類去完成

重點:(最重要的區別)

狀態模式需要各個狀態類,明確知道自己的下一個需要轉移的狀態是什麼,所有的狀態類一起組裝了請求的處理邏輯

責任鏈模式上的責任類,不需要不需要知道自己的下一個需要轉移的職責是哪個這個組裝過程需要交給環境類去完成

    比如,政府部分的某項工作,縣政府先完成自己能處理的部分,不能處理的部分交給省政府,省政府再完成自己職責範圍內的部分,不能處理的部分交給中央政府,中央政府最後完成該項工作。但是以上的責任的轉移,或者說在責任鏈上的移動,各個責任類不知道具體順序和下一個責任,鏈條的組裝過程是環境類(或客戶端完成的)

一般來說責任鏈重要的是環境類,通過環境類其指定各個責任類的執行順序,非常靈活

每個責任類只需要完成自己的工作其他的不需要考慮

但是還有一種寫法是責任鏈也是可以指定下一個責任類,那麼這個時候區分兩種模式的就要使用終極大殺器了

需要注意的是:狀態模式出現的根本原因是需要對自身的狀態進行改變

而責任鏈模式是對一個事件的處理

極大程度簡化了這些操作


3、策略模式(retrofit)

什麼叫做策略,我們可以把策略理解成備選,那麼策略模式就是用來解決當出現一個問題的時候,我們會有很多種備選方案,如何完美的利用這些備選方案,而又符合程式的設計美學,這就是策略模式的存在的必要性
可能你會認為那不就是一些if else 或者switch case 就可以解決的問題嗎,不錯,if else 確實可以非常有效的解決問題,但是如果出現需要擴充套件的情況呢?如果你的if else 部分的程式碼是不對外開放的,無法及時修改怎麼辦呢?
上面這些問題其本質就是使用if else 是不符合OCP原則的,也就是不能同時滿足對擴充套件開放,對修改關閉的原則,而使用策略模式就可以完美解決這個問題
例如:一個應用可能需要多種主題風格
我們就可以使用策略模式來實現主題的切換
步驟:
(1)建立一個主題介面
(2)建立一個維護主題介面的上下文,此上下文物件包含一個主題介面的引用,和設定主題的方法
(3)然後我們就可以實現主題介面的具體策略,例如主題方案1,方案2,方案....
(4)呼叫的時候我們只需要將對應的主題方案傳遞給上下文,然後呼叫上下文物件的設定主題的方法就可以了,最重要的是if else不見了
(5)那麼如果我們想要再新增一個主題方案怎麼辦?很簡單新增一個主題介面的實現類然後呼叫就可以
(6)這樣我們可以把主題介面,主題介面的上下文,預設的主題方案等這些東西作為上層封裝起來,關閉下層呼叫者的修改許可權,但是保留了其擴充套件的許可權


當然策略模式可以和其他模式結合起來使用例如:
當我們的應用裡面的主題過於複雜的時候我們就可以使用工廠模式去生產主題,將所有的主題的生產維護在一個主題工廠裡面


那麼兩者結合起來就是:
(1)使用者呼叫主題工廠生產一個主題
(2)使用者呼叫主題上下文物件切換指定主題
非常簡潔明瞭
可是有人會問,在客戶端呼叫的時候,還是會new一個具體的物件啊,這樣就會產生依賴,是的,這就是注入依賴要解決的問題咯,本文不做深入的探討


在舉例:
假如有一個電商網站系統,針對男性女性使用者要各自跳轉到不同的商品類目,並且所有的廣告位展示不同的廣告。在傳統的程式碼中,都是在系統中加入各種if else的判斷,硬編碼的方式。如果有一天增加了一種使用者,就需要改寫程式碼。使用策略模式,如果新增加一種使用者型別,只需要增加一種策略就可以

狀態模式和策略模式的比較
  實現目的不一樣!
  首先知道,策略模式是一個介面的應用案例,一個很重要的設計模式,簡單易用,策略模式一般用於單個演算法的替換,客戶端事先必須知道所有的可替換策略,由客戶端去指定環境類需要哪個策略,注意通常都只有一個最恰當的策略(演算法)被選擇。其他策略是同級的,可互相動態的在執行中替換原有策略,(注意關鍵是策略模式需要客戶端了解策略)

    而狀態模式的每個狀態子類中需要包含環境類(Context)中的所有方法的具體實現——條件語句,通過把行為和行為對應的邏輯包裝到狀態類裡,在環境類裡消除大量的邏輯判斷,而不同狀態的切換由繼承(實現)State的狀態子類去實現,當發現修改的當前物件的狀態不是自己這個狀態所對應的引數,則各個狀態子類自己給Context類切換狀態(有職責鏈模式思想)

    且客戶端不直接和狀態類互動,客戶端不需要了解狀態!(和策略不一樣),策略模式是直接依賴注入到Context類的引數進行選擇策略,不存在切換狀態的操作,客戶端需要了解策略!

聯絡:

    狀態模式和策略模式都是為具有多種可能情形設計的模式,把不同的處理情形抽象為一個相同的介面(抽象類),符合對開閉原則,且策略模式更具有一般性,在實踐中,可以用策略模式來封裝幾乎任何型別的規則,只要在分析過程中聽到需要在不同實踐應用不同的業務規則,就可以考慮使用策略模式處理,在這點上策略模式是包含狀態模式的功能的。