GOF提出的設計模式,其本質思想是封裝變化。故而,建立型模式封裝的是對象建立的變化,結構型模式封裝的是對象之間的協做與組合結構,行爲型模式則封裝了對象行爲的變化。所謂「行爲」,不正是函數所能要表達的嗎?在支持FP的編程語言中,函數成爲了一等公民,即它能夠脫離對象而單獨存在,也可以當作參數或返回值(高階函數)。因而,傳統的OO設計模式開始了變化,尤爲是行爲型模式。java
從函數的抽象角度看,任何行爲均可以理解爲是一個對類型進行轉換的函數,這是FP思想對OO設計模式的最大沖擊。例如Strategy模式與Command模式,前者封裝了算法策略的變化,後者則封裝了命令請求的變化。不管算法策略,仍是命令請求,均可以表現爲一個函數。程序員
譬如說將各類四則運算看作是一種算法策略,爲了應對具體計算的變化,在Java中咱們應該定義四則運算的策略接口:算法
public interface Strategy {
int compute(int a, int b);
}
public class Context {
private final Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void use(int a, int b) {
strategy.compute(a, b);
}
}複製代碼
接收兩個整數,而後通過計算返回一個整數。顯然,四則運算的調用者其實關注的不是Strategy
這個接口,而是compute
這個行爲。跟進一步,調用者其實關注的是將兩個整數轉換爲一個整數的行爲,他並不關心接口是什麼,函數名有是什麼,而是關注f(a, b) = c
這個函數。因而,在Scala中,策略模式的實現就變爲:編程
class Context(f: (Int, Int) => Int) {
def use(a: Int, b: Int): Int = f(a, b)
}複製代碼
固然,你能夠能夠爲這個函數定義一個類型,使其更加表意:設計模式
type Stategy = (Int, Int) => Int複製代碼
固然,若是面對的是一組策略行爲的封裝,且這些策略行爲的變化是一致的,使用一個接口將這些行爲封裝起來,在重用和表意角度講,彷佛又比單純使用函數更佳。Scala提供OO與FP兩種範式,算是一種騎牆的取巧,程序員須要依勢而爲。Scala給你提供了豐富而精彩的食材,若是你沒有將菜作得色香味俱全,不能怪食材很差,仍是本身太爛了。編程語言
Scala還提供了一種相似block的機制,稱之爲by name call。它接受的是一個語句塊,而非函數類型。因此要注意這種形式與無參函數的區別。此外,by name call同時還具備延遲調用的能力。例如,當咱們定義一個invoke
函數接受一個無傳入參數的函數時:函數
def invoke(f: () => Unit) = f()複製代碼
若是你向invoke
傳入println("scala")
,scala會報告錯誤:post
這是由於println("scala")
返回的是Unit
類型,而不是() => Unit
函數類型。使用by name call就沒有這個問題:this
f: => Unit
是一個語句塊,因此不能像函數那樣調用。咱們可使用這種方式來快捷實現Command模式。spa
因爲Java 8已經支持Lambda表達式,雖然它仍然不支持高階函數,可是做爲Java程序員,仍然有必要培養函數抽象的能力與習慣。在Java 8中使用Lambda,不只讓語法變得簡潔,還可讓調用者能夠脫離對具體某個接口的依賴,而僅僅依賴函數的抽象特徵。
FP的編程思想中,除了高階函數(包括Curry等)具備的抽象能力以外,還有一個好處是提供組合子能力。落實到Scala的語法上,就是偏函數(Partial Function)的andThen
,compose
與orElse
。
Pavel Fatin在文章《Design Patterns in Scala》用OO設計模式中的Chain of Responsibility(職責鏈)模式來對比組合子,其實仍是比較牽強的。或者說,FP思想中的組合子遠遠比職責鏈模式更強大。在Elixir語言中,甚至還提供了管道操做符|>
實現這種函數的組合。而我在博客《Scala中的Partial Function》中已經很是詳解地介紹了Scala的偏函數,你們能夠移步閱讀。
若是真要對比,那麼結合Scala的語法來看,則orElse
能夠很是方便地模擬職責鏈模式,而andThen
則近似於管道-過濾器模式。其實我在OO語言中,不多運用GOF標誌的職責鏈模式,也就是當尋找到具體職責的承擔者時,履行職責後便可退出的方式;而是對這種模式進行調整,讓其在履行職責後繼續執行next
的職責,又近乎於管道-過濾器了。
因此說,設計模式的運用妙乎於心,講究應勢而變。在融入FP思想後,要從本質思想去面對這些模式,不拘泥於OO仍是FP,彷佛纔是將來編程的取捨之道。