摘要:面向對象常見的設計模式有策略模式、模板方法、觀察者模式、責任鏈模式以及工廠模式,使用Lambda表達式(函數式編程思維)有助於避免面向對象開發中的那些固定代碼。如果使用函數式編程思維,那麼職責鏈模式就直接了——y=f(x)和z=g(x)這兩個方法都是要對x做處理,那麼如果將這兩個函數組合在一起,就會形成r=f(g(x))的情況,也就是可以使用Lambda表達式中的addThen來串聯起多個處理過程。

設計模式是過去的一些好的經驗和套路的總結,但是好的語言特性可以讓開發者不去考慮這些設計模式。面向對象常見的設計模式有策略模式、模板方法、觀察者模式、責任鏈模式以及工廠模式,使用Lambda表達式(函數式編程思維)有助於避免面向對象開發中的那些固定代碼。下面挑選了策略模式和職責鏈模式兩個案例進行分析。

案例1:策略模式

用了 Lambda 之後,發現可以忘記設計模式了

當我們解決一個問題有不同的解法的時候,又不希望客戶感知到這些解法的細節,這種情況下適合使用策略模式。策略模式包括三個部分:

  • 解決問題的算法(上圖中的Strategy);
  • 一個或多個該類算法的具體實現(上圖中的ConcreteStrategyA、ConcreteStrategyB和ConcreteStrategyC)
  • 一個或多個客戶使用場景(上圖中的ClientContext)

面向對象思路

首先定義策略接口,表示字符串的處理算法:


用了 Lambda 之後,發現可以忘記設計模式了


然後定義具體的實現類,即不同的驗證算法:


用了 Lambda 之後,發現可以忘記設計模式了


最後定義客戶使用場景,代碼如下圖所示。Validator是爲客戶提供服務時使用的上下文環境,每個Valiator對象中都封裝了具體的Strategy對象,在實際工作中,我們可以通過更換具體的Strategy對象來進行客戶服務的升級,而且不需要讓客戶進行升級。


用了 Lambda 之後,發現可以忘記設計模式了


函數式編程思路

如果使用Lambda表達式考慮,你會發現ValidationStrategy就是一個函數接口(還與Predicate具有同樣的函數描述),那麼就不需要定義上面那些實現類了,可以直接用下面的代碼替換,原因是Lambda表達式內部已經對這些類進行了一定的封裝。


用了 Lambda 之後,發現可以忘記設計模式了


案例2:責任鏈模式

在某些場景下,需要對一個對象做一系列的工作,這些工作分別是由不同的類完成的,這時候就比較適合使用責任鏈模式。責任鏈模式的主要組成部分包括三個:

  • 管理操作序列的抽象類,在該抽象類裏有會有一個對象記錄當前對象的後繼操作對象;
  • 一些具體的操作對象,這些操作對象會以一個鏈表的形式組織起來
  • 一個使用該模式的客戶端組件,該組件只需要跟一個組件打交道就好,不需要跟很多個操作對象耦合在一起。


用了 Lambda 之後,發現可以忘記設計模式了


面向對象思路

首先看下我們這裏定義了一個抽象類ProcessingObject,其中successor字段用於管理該對象的後繼操作對象;handle接口作爲對外提供服務的接口;handleWork作爲實際處理對象的操作方法。


用了 Lambda 之後,發現可以忘記設計模式了


接下來可以定義兩個具體的操作對象,如下面代碼所示。PS:這裏《Java 8實戰》書中用的是replaceAll方法是不太合適的,這個點可以參考我們之前的文章——020:舉幾個String的API以及案例 )。


用了 Lambda 之後,發現可以忘記設計模式了


最後,你就可以在Client中將這上面兩個具體的操作類對象構成一個操作序列,參見下面的代碼:


用了 Lambda 之後,發現可以忘記設計模式了


函數式編程思路

如果使用函數式編程思維,那麼職責鏈模式就直接了——y=f(x)和z=g(x)這兩個方法都是要對x做處理,那麼如果將這兩個函數組合在一起,就會形成r=f(g(x))的情況,也就是可以使用Lambda表達式中的addThen來串聯起多個處理過程。


用了 Lambda 之後,發現可以忘記設計模式了


上面是利用Java原生的Lambda表達式實現的職責鏈模式,我們也可以使用前面一篇文章——vavr:讓你像寫Scala一樣寫Java)中介紹過的vavr庫來實現,代碼如下所示:


用了 Lambda 之後,發現可以忘記設計模式了


總結

可以看出,函數式編程思維跟面向對象編程思維的思考方式是不同的,表達力更強,因此,作爲開發者是時候認真學習下函數式編程思維了,作爲Java開發者,我準備先從Lambda表達式開始學起。

相關文章