1. 程式人生 > >【Scala】Cake模式和依賴注入

【Scala】Cake模式和依賴注入

依賴注入(Dependency Injection)和控制反轉(Inversion of Control)

Dependency Injection & Inversion of Control是Martin Fowler在2004年所提出來的一個概念,Martin Fowler在這篇文章中指出,DI可以有三種形式來實現。這觀念以後有Spring專案和Google實現出來,變成了Java Enterprise應用中不可或缺的一部分。

控制反轉是一個重要的面向物件程式設計的法則來削減計算機程式的耦合問題。控制反轉一般分為兩個型別,依賴注入(Dependency Injection)和依賴查詢(Dependency Lookup)。依賴注入應用廣泛。

許多應用程式都是由兩個或更多的類通過彼此的合作來實現業務邏輯,這使得每個物件都需要與其合作的物件(也就是它做依賴的物件)的引用。如果這個獲取過程要靠自身實現,那麼這將導致程式碼高度耦合並且難以測試。
應用控制反轉,物件在被建立的時候,由一個調控系統內所有物件的外界實體,將其所依賴的物件的引用,傳遞給它。也可以說,依賴被注入到物件中。所以,控制反轉是關於一個物件如何獲取它所依賴的物件的引用——這個責任的反轉。

IoC模式,系統中通過引入實現了IoC模式的IoC容器,即可由IoC容器來管理物件的生命週期、依賴關係等,從而使得應用程式的配置和依賴性規範與實際的應用程式程式碼分開。其中一個特點就是通過文字的配置檔案進行應用程式元件間依賴關係的配置,而不用重新修改並編譯具體的程式碼。
對於Java程式而言,IoC模式可以看做是工廠模式的昇華,可以把IoC看做是一個大工廠,只不過大工廠要生成的物件都是在XML檔案中給出定義的,然後利用Java的反射程式設計,根據XML中給出的類名生成相應的物件。從實現來看,IoC是把以前的工廠方法裡寫死的物件生成程式碼,改變為由XML檔案來定義,也就是把工廠和物件生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性。

Scala中的蛋糕模式(cake pattern)

依賴注入一般需要三個組成部分:

  1. 依賴消費者
  2. 依賴項的宣告(依賴消費者需要的依賴項)
  3. 將物件引用或型別注入到依賴消費者的方法

蛋糕模式(cake pattern)是Scala實現依賴注入的方法之一,它利用Scala Mixin功能,讓物件被建立時,才把相依的原件,透過Mixin的方式綁在一起。

蛋糕模式的組成部分:

  • 配置特質(Configuration Trait):該結構定義了用於注入的物件的抽象
    配置特質是對被依賴的元件提供層(the dependent component providers layers)的包裝,它提供了根元件所依賴的行為和資料
  • 具體的配置特質(Concrete Configuration Traits):該結構定義了被依賴的結構具體是如何建立的,比如通過配置檔案、資料庫或者維護在記憶體的資源
  • 內容特質(Context Trait):該特質用於確定被載入的具體配置
  • 依賴元件(Dependent Component):該元件依賴於具體配置結構提供的物件

蛋糕模式的實際問題:

  • 將所依賴的物件配置給應用程式程式碼使得在執行時進行調整更換成為可能。這些配置資訊由XML檔案、資料庫或者其他合適的檔案提供
  • 確定具體的配置可以在工廠物件中進行

演示例子

Config特質定義了load方法和text值,load方法在例項化時將被執行,用於載入配置資訊。
一個具體的配置型別定義為InMemoryConfig,它定義了具體的Config行為。

trait Config {
  load
  val text: String
  def load: Unit
}

trait InMemoryConfig extends Config {
  lazy val text = "Hello"
  def load = println("load: " + text)
}

Context特質用來表示蛋糕模式的內容物件,MyContext特質使用this子型別註解(self type annotation)指定Config型別將被混入到當前類或物件中,於是Config特質中的資料和方法就好像是定義在該特質中的一樣。
注意,多個特質都可以被混入到this引用中,比如this: ConfigContext with DAOContext with ConnectionManagerContext

trait Context

trait MyContext extends Context {
  this: Config =>
  def welcome = this.text
}

Env這個物件是單例模式在Scala中的語法化表示,它繼承了混入InMemoryConfig特質的MyContext,它很好的表示了依賴嵌入環境。

object Env extends MyContext with InMemoryConfig

執行println(Env.text)將列印:

load: Hello
Hello

蛋糕模式的優缺點

優點
1. 沒有使用框架,僅使用語言特性
2. 型別安全——缺失的依賴項在編譯時被發現
3. 功能強大——通過實現合適的依賴提供方法進行協助嵌入
缺點是程式碼模板複雜

參考資料