DI等於介面? 誤會可大了! — 3 (final)

Z-xuan Hong
May 26, 2022

--

前幾天在靠北工程師看到一則貼文,內容大致如下:

抱怨公司的專案,整體架構上使用過多的介面,每個類別都有一個介面,假設N個類別,就有2*N個元件需要維護,過度複雜。

當爭議的議題出現時,可想像留言區通常會多方激烈論戰,觀點非常多,有人說DI就是這樣、有人說Java就是這樣、有人說Spring就是這樣、也有人說介面不等於DI等等。

看到大家的辯論,讓我意識到大部分開發者對介面與DI的概念有一定程度的誤解,因此想撰寫一篇文章來跟大家闡述介面與DI之間的關係。(當然這只是我開發多年與看書消化的觀點,也不一定正確,如果有任何疑問,歡迎下方留言多多討論)

此文章總共有三篇,每篇皆嘗試釐清一個概念,此篇為最後一篇:

  • 了解介面所要解決的問題與使用時機 (1)。
  • 了解DI所要解決的問題與使用時機 (2)。
  • 了解為什麼DI不等於介面、介面不等於DI (3)。

介面解決之問題

在第一篇文章中,我們提到了介面要解決的問題,不知道大家還記得嗎?

  • 封裝shared dependency。
  • 封裝volatile dependency。
  • 封裝multiple implementations。
  • 遵守depedency inversion principle。

當宣告介面不是為了解決上述問題時,需要回頭檢視一下系統的設計是否出了一些問題。

每個介面都是需要維護的元件,要確保介面增加帶來的價值遠遠高於其成本,長遠下來才能降低系統維護成本。

DI & DI Container解決之問題

在二篇文章中,我們提到了DI & DI Container要解決的問題,不知道大家還記得嗎?

DI

  • 確保物件生成的方式統一。
  • 確保物件從外部獲得dependency,而不是自己產生。

DI Container

  • 組裝應用程式 (object composition)
  • 控制生命週期
  • AOP

當所有應用程式內的物件皆使用DI概念時,物件會放棄物件的生成、生命週期的控制,從最小元件到最大元件皆是如此,最終,所有物件的生成、生命週期的控制、組裝都會下放於程式進入點 (main entry point)。

當上述概念都在程式進入點進行時,我們可以使用DI Container去解決這些問題,而不使用DI Container自己手動在程式進入點組裝物件、生成物件、生命週期控管的方式也有人使用,這稱之為Pure DI

DI & DI Container & 介面 Overlapping

當讀者都了解DI、DI Container、介面的概念是什麼、解決什麼問題之後,我們就能開始分析介面是否等於DI了。

先說結論: DI不等於介面、介面不等於DI、但兩個概念可以同時運用。

當使用介面時,我們需要產生實作此介面的類別的物件,在DI出現之前,我們會使用singleton + factory來封裝這些物件產生的過程 (第二篇文章),而DI正好也能解決此問題。

DI的概念會讓外部使用者注入實作此介面的類別的物件,而使用介面的客戶端就不需要透過singleton + factory來獲取對應的物件,進而簡化整個程式碼。

所以說,當我們宣告介面解決shared、volatile、multiple implementation、等問題時,通常會搭配DI的概念來提供需要的物件,這就是介面與DI同時應用的部分。

但大部分時候儘管沒有介面我們依然會使用DI來組裝複雜的物件 (第二篇文章),透過DI注入的方式可以降低物件與物件之間的耦合性,讓系統更朝向物件組裝的方式。

這就是為什麼我說: DI不等於介面、介面不等於DI、但兩個概念可以同時運用。

後序

這篇文章是DI/介面系統最後一篇,希望透過我這三篇文章的講解,大家已經了解介面、DI的使用方式,相信如果能夠掌握這兩個概念,對於專案長久的發展下會有莫大的幫助。

結論

  • DI不等於介面、介面不等於DI、但兩個概念可以同時運用。
  • 釐清各個概念是什麼、解決什麼問題才有辦法分析彼此的差異、相同的部分。

--

--

Z-xuan Hong

熱愛軟體開發、物件導向、自動化測試、框架設計,擅長透過軟工幫助企業達到成本最小化、價值最大化。單元測試企業內訓、導入請私訊信箱:t107598042@ntut.org.tw。