了解Node.js Nestjs框架的模塊機制,聊聊實現原理( 二 )


初期 , 我們在實現應用的時候 , 在滿足當時需求的情況下 , 就會實現出 B 和 C 類的寫法 , 這本身也沒有什么問題 , 項目迭代了幾年之后 , 都不一定會動這部分代碼 。 我們要是去考慮后期擴展什么的 , 是會影響開發效率的 , 而且不一定派的上用場 。 所以大部分時候 , 我們都是遇到需要抽象的場景 , 再對部分代碼做抽象改造 。
// 改造前class B{ contructor(){ this.a = new A(); }}new B()// 改造后class D{ contructor(a){ this.a = a; }}new D(new A())new D(new X())按照目前的開發模式 , CBD三種類都會存在 , B 和 C有一定的幾率發展成為 D , 每次升級 D 的抽象過程 , 我們會需要重構代碼 , 這是一種實現成本 。
這里舉這個例子是想說明 , 在一個沒有任何約束或者規定的開發模式下 。 我們是可以自由的寫代碼來達到各種類與類之間依賴控制 。 在一個完全開放的環境里 , 是非常自由的 , 這是一個刀耕火種的原始時代 。 由于沒有一個固定的代碼開發模式 , 沒有一個最高行動綱領 , 隨著不同開發人員的介入或者說同一個開發者不同時間段寫代碼的差別 , 代碼在增長的過程中 , 依賴關系會變得非常不清晰 , 該共享的實例可能被多次實例化 , 浪費內存 。 從代碼中 , 很難看清楚一個完整的依賴關系結構 , 代碼可能會變得非常難以維護 。

了解Node.js Nestjs框架的模塊機制,聊聊實現原理

文章插圖

那我們每定義一個類 , 都按照依賴注入的方式來寫 , 都寫成 D 這樣的 , 那 C 和 B 的抽象過程就被提前了 , 這樣后期擴展也比較方便 , 減少了改造成本 。 所以把這叫All in 依賴注入 , 也就是我們所有依賴都通過依賴注入的方式實現 。
可這樣前期的實現成本又變高了 , 很難在團隊協作中達到統一并且堅持下去 , 最終可能會落地失敗 , 這也可以被定義為是一種過度設計 , 因為額外的實現成本 , 不一定能帶來收益 。
2.3 控制反轉
既然已經約定好了統一使用依賴注入的方式 , 那是否可以通過框架的底層封裝 , 實現一個底層控制器 , 約定一個依賴配置規則 , 控制器根據我們定義的依賴配置來控制實例化過程和依賴共享 , 幫助我們實現類管理 。 這樣的設計模式就叫控制反轉 。
控制反轉可能第一次聽說的時候會很難理解 , 控制指的什么?反轉了啥?
猜測是由于開發者一開始就用此類框架 , 并沒有體驗過上個“Express、Koa時代” , 缺乏舊社會毒打 。 加上這反轉的用詞 , 在程序中顯得非常的抽象 , 難以望文生義 。
前文我們說的實現 Koa 應用 , 所有的類完全由我們自由控制的 , 所以可以看作是一個常規的程序控制方式 , 那就叫它:控制正轉 。 而我們使用 Nest , 它底層實現一套控制器 , 我們只需要在實際開發過程中 , 按照約定寫配置代碼 , 框架程序就會幫我們管理類的依賴注入 , 所以就把它叫作:控制反轉 。
本質就是把程序的實現過程交給框架程序去統一管理 , 控制權從開發者 , 交給了框架程序 。
控制正轉:開發者純手動控制程序
了解Node.js Nestjs框架的模塊機制,聊聊實現原理

文章插圖

控制反轉:框架程序控制
了解Node.js Nestjs框架的模塊機制,聊聊實現原理

文章插圖

舉個現實的例子 , 一個人本來是自己開車去上班的 , 他的目的就是到達公司 。 它自己開車 , 自己控制路線 。 而如果交出開車的控制權 , 就是去趕公交 , 他只需要選擇一個對應的班車就可以到達公司了 。 單從控制來說 , 人就是被解放出來了 , 只需要記住坐那趟公交就行了 , 犯錯的幾率也小了 , 人也輕松了不少 。 公交系統就是控制器 , 公交線路就是約定配置 。
通過如上的實際對比 , 我想應該有點能理解控制反轉了 。
2.4 小結
從 Koa 到 Nest , 從前端的 JQuery 到 Vue React 。 其實都是一步步通過框架封裝 , 去解決上個時代低效率的問題 。
上面的 Koa 應用開發 , 通過非常原始的方式去控制依賴和實例化 , 就類似于前端中的 JQuery 操作 dom , 這種很原始的方式就把它叫控制正轉 , 而 Vue React 就好似 Nest 提供了一層程序控制器 , 他們可以都叫控制反轉 。 這也是個人理解 , 如果有問題期望大神指出 。
下面再來說說 Nest 中的模塊 @Module , 依賴注入、控制反轉需要它作為媒介 。

推薦閱讀