可能有人會覺得,Part 2開頭所描述的功能,用MonoBehaviour-base寫會快很多。
因此我在這一篇比較一下DI與MonoBehaviour-base在開發上的不同。
直接講結論,其實沒什麼不同
即使你使用MonoBehaviour-base來做開發,只要你致力於撰寫良好的程式碼,也仍然可以寫出良好的軟體架構。不過DI框架可以幫助你更容易寫出來。
MonoBehaviour的原生優勢與劣勢
在開發初期,MonoBehaviour-base開發速度的確比較快,而且真的挺快的。
MonoBehaviour與其它原生的Component類別,讓初學者比較容易上手。也讓從零開始的開發初期保持在幾乎無痛的狀態。在開發小規模的遊戲時,這個優勢十分明顯。在Game Jam或是開發遊戲雛形時,可以不用考慮撰寫良好程式碼時,MonoBehaviour為你創造很好的開發速度。
但為了其優勢所換來的問題,就如這一系列文章不斷提起的,是為了取得物件實體而大量使用singleton與繼承MonoBehaviour,寫出了高耦合性的程式碼,並進而衍生出的軟體架構問題。
在開發到一定規模時,只要架構稍有不佳,MonoBehaviour-base開發速度會開始急遽下降。
使用MonoBehaviour的原則
- 協助渲染的腳本,像是控制動畫的腳本、場景
(透過SerializeField來獲取renderer或animator) - 需要物理碰撞與觸發(透過OnCollision與OnTrigger系列函式)
- 需要使用coroutine的腳本(有時也可以用DI來解決)
- 其他與遊戲主邏輯無關的支援腳本,例如:FPS顯示、debug介面
Dependency Injection的優勢
使用DI的優勢在於,方便的獲取相依性。
基於這個優勢,衍生出下面的好處。
1. 更容易寫出可測試的程式碼:
我們都知道很難為MonoBehaviour寫測試,最主要的原因是難以透過介面來模擬與更換其相依物件。也就是說,很難為其注入相依性。
那麼注入相依性的工作就交給DI框架來處理吧!
2. 更加符合單一職責原則(Single Responsibility Prinsiple):
一般的狀況,尋找物件不外乎serialized field、GetComponent()或singleton。而且通常會寫在腳本的Awake()或Start()函式內。
藉由DI框架,尋找其它物件的職責就與本身的邏輯分離出來了。DI框架會負責提供相依性給物件。
3. 藉由上面2項優勢,你可以更加容易的切割出模組:
你可以很容易的為單一模組創建出執行的環境。打個比方說,市面上主流的手機遊戲,總是有許多的系統,你可以很簡單的測試各個單一的系統。當設計師需要更換與移除系統時,你也可以無痛的進行修改。
4. 穩定的開發速度:
你的程式碼不會再因為高耦合性衍生出問題,減少了解決衍生問題的時間,穩定了開發速度。
DI不是魔法,它只是一個手段,剛好解決了我們利用Unity開發遊戲時的根本問題。
下一篇文章會接續Part 2的功能,以進一步的例子來解釋如何調整遊戲參數、設定檔的注入、以及scriptable object的使用。