天天看點

依賴注入

即控制反轉,目的是了減少耦合性,簡單來說就是使用開放式來擷取需要的資源。

這裡說的資源主要是在開發過程中使用到的資源,包括配置項;資料庫連接配接、Memcache、接口請求等系統級的服務;以及業務級使用到的執行個體等。

引入依賴注入的目的不僅是為了增加一個類,而是為了更好的對資源進行初始化、管理和維護。下面将進行詳細的說明。

很多時候,類之間會存在依賴、引用、委托的關系,如A依賴B時,可以這樣使用:

這種方式在A内限制限制了B的執行個體對象,當改用B的子類或者改變B的建構方式時,A需要作出調整。這時可以通過依賴來改善這種關系:

再進一步,可以使用DI對B的對象進行管理:

這樣的好處?

一方面,對于使用A的客戶(指開發人員),不需要再添加一個B的成員變量,特别不是全部類的成員函數都需要使用B類服務時。另一方面在外部多次初始化A執行個體時,可以統一對B的建構。

為友善使用,調用的方式有:set/get函數、魔法方法setX/getX、類變量$fdi->X、數組$fdi['X'],初始化的途徑有:直接指派、類名、匿名函數。

DI相當于一個容器,裡面可以放置基本的變量,也可以放置某類服務,甚至是像檔案句柄這些的資源。在這容器裡面,各個被注冊的資源隻會存在一份,也就是當被注冊的資源為一個執行個體對象時,其效果就等于單例模式。

是以,儲存在DI裡面的類,不需要再編寫擷取單例的代碼,直接通過DI擷取即可。

例如很多API的服務元件以及其他的一些類,都實作了單例擷取的方式。分别如:

微網誌接口調用:

七牛雲存儲接口調用:

QQ開放平台接口調用:

如果使用DI對上面這些服務進行管理,則上面三個類乃至其他的類對于單例這塊的代碼都可以忽略不寫。注冊代碼如下:

上面是通過類名來進行延遲加載,但需要各個類提供public的無參數的構造函數。如果各個服務需要進行初始化,可以将初始化的工作放置在onInitialize()函數内,DI在對類執行個體化時會回調此函數進行初始化。

這裡引入DI,更多是為了“一處建立,多處使用”, 而不是各自建立,各自使用。

考慮以下場景:假設有這樣的業務資料需要緩存機制,是以可注冊一個實作緩存機制的執行個體:

然後提供給多個用戶端使用:

當需要切換到MC或者Redis緩存或者多層緩存時,隻需要修改對緩存機制的注入即可,如:

依賴注入的一個很大的優勢就在于可以推遲決策,當需要用到某個對象時,才對其執行個體化。可以讓開發人員在一開始時不必要關注過多的細節實作,同時也給後期的擴充和維護帶來極大的友善。

再上一層,假設未來我們需要更進階的緩存服務,那麼我們可以在不影響用戶端使用的情況下,輕松更新。

未來的可配置化的多級緩存政策

以下是一個模拟的使用場景,但依然對現在的項目有一定的幫助。假設我們現在有一個MC叢集的緩存且引入了DI,使用如下:

假設現在發現一層緩存存在穿透情況,為保證伺服器的穩定性,我們已開發實作了多層緩存政策,并且可以通過簡單配置即可實作,隻需要對DI容器裡面的cache執行個體進行更新,其他用戶端的調用即可馬上享受到緩存更新的優質服務。更新涉及改動的代碼如下:

備注:關于多級緩存政策,後續會提供源代碼和重用庫,或者讀者提供 (^_^)。

延遲加載可以通過DI中的類名初始化、匿名函數和參數配置(未實作)三種方式來實作。

延遲加載有時候是非常有必要的,如在初始化項目 的配置時,随着配置項的資料增加,伺服器的性能也将逐漸受到影響,因為配置的内容可能是寫死,可能來自于資料庫,甚至需要通過接口從背景調用擷取, 特别當很多配置項不需要使用時。而此時,支援延時加載将可以達到很好的優化,而不用擔心在需要使用的時候忘記了初始化。進而很好的提高伺服器性能,提高響 應速度。

如對一些耗時的資源先進行匿名函數的初始化:

在我看來,PHP裡面是不應該使用全局變量(global和$_GLOBALS),更不應該到處使用。

用了DI來管理,即可這樣注冊:

然後這樣使用:

也許有人會想:僅僅是換個地方存放變量而已嗎?其實是換一種思想使用資源。

以此延伸,DI還可用于改善優化另外兩個地方:通過include檔案途徑對變量的使用和變量的多層傳遞。

變量的多層傳遞,通俗來說就是漂洋過海的變量。