最近工作上接手別人寫的程式。我發現這份程式用了一個我之前不太懂的設計模式 (design pattern),叫作相依注入 (dependency injection, DI)。由於這份程式多處使用 DI,讓我不得不先了解它,才知道這份程式要怎麼改會比較順利。
我之前就曾接觸、學習過 DI design pattern,但沒抓到其精髓(也就是不知道它的好處),所以後來也不知道怎麼用,也就忘了它。今天在 YouTube 找到一部 DI 的入門教學,那位講者舉了一個好懂的例子讓我了解 DI 的優點。
他舉的例子是汽車製造。一輛汽車由車輪、引擎、…等組成。若一家汽車組裝廠什麼都自己來、包山包海,不止組裝汽車,還製造車輪、引擎、…,這樣是有些缺點的。以組裝的彈性度來看,他們只有自家製造的東西可以選。
但如果這家汽車組裝廠改走另一種策略 – 自己不製造零件,只負責買進零件、組裝。那麼這家汽車廠就能生產更多樣的汽車。汽車的組成依賴於 (depends on) 零件,而這家工廠改變自行製造零件的策略就是解耦相依 (decouple dependencies),而買進零件來組裝就是注入相依 (dependency injection)。
用一些程式設計的術語來說,DI 這種設計模式讓零件更抽象,零件不再是自家生產的特定型號,可以是任何一家生產的。又由於工廠不再負責零件生產,所以要新型號零件不須更動工廠,只要從外面買進來即可。
回到程式設計, DI 設計模式帶來的優點是:一支經過解耦相依的程式碼不再綁定特定相依,可以透過注入相依的方式輕易替換不同相依的實作。這對單元測試 (unit test) 很有利,我們可以把一些實際運作上很複雜的相依,在測試階段用簡單的模擬相依替代。例如要測試一支圖片讀取程式,實際運作要完整的資料庫與後端程式環境,但有了 DI,可在不更動主程式的情況下,可以寫一支簡單的模擬資料庫與後端程式作相依注入。
解耦相依帶來的另一好處就是不須更動主程式下,支援新的相依,減少主程式因為要作修改出現 bugs 的機會。這實際上的確容易遇到,比如不用 DI 寫的程式,要加入一組新功能,一種作法就是多一個 conditional block,但如果沒注意整支程式怎麼寫,舊有的 conditional blocks 可能就會對其造成不良的影響產生 bugs,也就是 – 你想加新功能的程式碼,還要看舊有功能會不會對其造成不良影響!程式碼少可能還好,程式碼一多就麻煩了!