選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
8 分鐘閱讀時間 (1516 個字)

使用 IoC 進行專案的客製

mr-bochelly-IBKyH0V3rew-unsplash

前言

在進行新專案的開發時,我們通常會用一個已經做好的產品當作基底開始實作給新客戶的需求,而在開發的過程中必定會有一部份是只有某間公司需要而其他公司不需要的功能,這時候就要進行所謂的客製,而客製又分為

1. 在產品上沒有,純粹新增功能
2. 在產品上有,但需要針對客製的部分做一點修改

兩種情況。這篇文章會以我對客製化的瞭解做一點簡單的分享。

什麼是 IoC

IoC 是 Inversion of Control (控制反轉) 的縮寫,其為一種設計思想,降低程式之間的耦合度,增加維護時的便利性。

什麼是 DI

DI 是 Dependency Injection (依賴注入) 的縮寫,是其中一個實作 IoC 的方法。簡單來說就是將被依賴的物件傳送給被動接收物件。
舉例來說,學校需要老師教書,沒有老師學校就需要再去尋找別的老師,在這情況下
學校 = 被動接收物件
老師 = 被依賴的物件
因此學校會依賴老師,但如果今天有一個負責提供老師的機關 (稱為依賴注入容器,DI Container),學校就只要跟機關要老師,而不用管說沒有老師怎麼辦,因為那是機關要決定的事。
換成程式來說就是將要負責實作的類別提供給呼叫該介面的人,詳細的例子會在以下說明。

為什麼要用 IoC

想像一下以下情境:
學校裡有一間教室,這間教室是專門給數學老師教數學用的。
以直覺來說寫成程式碼可能會像以下這樣:


而當今天要把教室變成給英文老師使用時,程式碼可能要改成這樣:



這樣其實並不是一個好的設計,因為這間教室過於依賴 MathTeacher 與 EnglishTeacher 這兩個物件,當今天換不同科目的老師教時,我們必須回到 ClassRoom 一個一個手動修改老師的類別,大大降低了便利性。
為了解決這個問題,我們需要用到 Interface (介面) 的幫助。
介面簡單來說就是只負責定義一組規範,將實作的內容交由實作他的人去決定。
例如上述的問題可以改成下面的範例:



為什麼寫某個 DI Container 呢? 就像剛剛介紹 DI 的例子,如果有一個 Container 負責記錄針對每個介面所要提供的實作類別,那這支程式不就完全不用改了嗎? 可以省下我們修改以及重新編譯的時間。
但今天如果要更換實作 ITeacher 的類別時當然還是需要做一點修改,只不過是改在 DI Container 裡面,好處就是各個實作對象統一在一個檔案裡面比較明瞭,並且修改後不需重新編譯即可執行。

DI Container 的實作方式有很多種,常見的有:
  • Autofac
  • Unity
  • Ninject
  • Structuremap
  • Spring (我們專案使用的)
    等等...
上述的例子也正呼應了 IoC 的概念,以往都是在宣告變數時就定義了這個變數是什麼樣的類別,是屬於從上到下的流程。但使用 DI Container 讓我們在提供實作類別的時候才決定這個變數應該做什麼事,將流程整個反轉了。

實際客製

真正對產品進行客製化時,我們必須將上述的概念套用至專案。

首先設定好我們的 DI Container (使用 Spring 為例)

再來就可以透過呼叫 DI Container 來取得該實作的類別



如同我在前言所說,在客製時會遇到以下兩種情況:

  1. 產品無現有功能,專案需自行新增業務邏輯的情境
    以上圖的 DocumentBLL 來說,我們可以另外新增一支 DocumentBLL _Customized 然後將要新增的功能宣告在 IDocumentBLL _Customized,並且實作他

    接著就可以在 DI Container 設定要實作 IDocumentBLL _Customized 的類別

    然後就可以透過 DI Container 取值了
  2. 產品已有現有功能,但專案的業務邏輯與產品不同的情境
    一樣是新增一支 DocumentBLL _Customized,然後繼承原來的 DocumentBLL 並實作 IDocumentBLL 
    接著修改原來的 IDocumentBLL 的實作類別為 DocumentBLL _Customized

    原來呼叫 IDocumentBLL 的內容不變,因為改變實作類別這件事直接在 Config 做了,所以取到的實作類別會是 DocumentBLL _Customized
    修改的內容寫在 DocumentBLL _Customized,並且 Override 掉原本的方法即可
    如此一來便可以在不修改到呼叫端 (Controller) 的情況下進行原有功能的修改

常見問題

  1. 為什麼不直接改產品的 Code,要另外拉出一支方法做修改?
    因為專案開發的同時產品也在開發,而產品算是所有專案的一個基底,所以專案必須定期 Merge 產品的 Code 進來。
    當專案與產品在開發的同時都對產品的同一支程式做修改時容易產生衝突,造成 Merge 上的困難。
  2. 承上,那如果直接改在基底,那 Merge 的時候不就沒衝突,可以直接拿來用了嗎?
    因為既然是專案就必定有只屬於某一間公司的功能,將客製化的東西直接放在基底就違反了產品功能通用的原則。
  3. 既然 Override 掉原有功能,那當產品的功能更新時不就跟不到了嗎?
    的確有這個可能,所以理想情況是需要修改的地方在產品就已經自己抽成一個方法了,這樣就可以直接 Override 該方法。

參考資料

維基百科 - 控制反轉

IoC基本概念介紹

IOC(控制反轉) , DI(依賴注入) 深入淺出~~

更新 Mac App 憑證
Microsoft Botframework + Adaptive Cards 快速打造 Chatb...
 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/19, 週日

Captcha 圖像