爲什麼依賴注入出現的頻率這麼高?

前言

早上坐地鐵,腦子裏突然閃到依賴注入這個詞,然後努力回憶一下,覺得似懂非懂的,很模糊。
依賴注入在日常項目裏出現的頻率真的是很高了,不管是.net core,還是angular都有使用,那麼依賴注入究竟有什麼優勢呢?

一、什麼是依賴注入

依賴注入(Dependency Injection)是用於實現控制反轉(Inversion Of Control)的最常見的方式之一。
那麼什麼是控制反轉?

控制反轉
是面向對象編程中的一種設計原則,常用於解耦。因爲大多數應用程序都是由兩個或是更多的類通過彼此的合作來實現業務邏輯,這使得每個對象都需要獲取與其合作的對象(也就是它所依賴的對象)的引用。如果這個獲取過程要靠自身實現(也就是通過new一個你要使用的對象),那麼這將導致代碼高度耦合並且難以維護和調試。而控制反轉就是爲了解決這個問題。
簡單來說:獲得依賴對象的過程被反轉了”。控制被反轉之後,獲得依賴對象的過程由自身管理變爲了由IOC容器主動注入

接着來說依賴注入
依賴注入(DI)不需要直接new來獲得這個對象,而是通過相關的容器控制程序,來將要使用的對象在外部new出來並注入到A類裏的引用中,具體獲取的方法和對象被獲取時的狀態則由配置文件(如XML)來指定。
簡單的來說就是依賴注入提供了裝配能力,框架負責new對象,以及把他們組織起來,你唯一需要做的就是調用業務方法。
再翻譯成大白話來說,如果你想喫番茄炒蛋,如果在家自己做的話,需要切番茄,打雞蛋,起鍋放油炒等等等步驟很麻煩,那我可以直接去找個餐廳,點一份番茄炒蛋,我不管你是怎麼做的,直接喫就行了。
於是:

  • 控制反轉就是你要喫番茄炒蛋,但是又覺得麻煩不想做的解決方案。
  • 依賴注入其實就是你去餐廳點菜這個實現方式,也是解決方案的具體實現。
  • 番茄炒蛋就是你要用的對象。
  • 番茄炒蛋的配方就是你的配置文件。

最後做個總結:
控制反轉(IOC)是實現解耦的一種解決方案,依賴注入是控制反轉的一種實現方式,它提供了裝配能力,框架負責new對象並且管理他們,當你要使用的時候告訴他要使用什麼就可以了(聽起來很像工廠模式?)
試着描述一下這個過程:
對象A依賴於對象B,當對象 A需要用到對象B的時候,IOC容器就會立即創建一個對象B送給對象A。IOC容器就是一個對象製造工廠,你需要什麼,它會給你送去,你直接使用就行了,而再也不用去關心你所用的東西是如何製成的,也不用關心最後是怎麼被銷燬的,這一切全部由IOC容器包辦。

二、依賴注入的優缺點

與其說是依賴注入的優缺點,不如說是控制反轉IOC的優缺點。
先說優點,拿上面那個番茄炒蛋的例子來說:
在這裏插入圖片描述

第一、番茄炒蛋作爲被喫的菜而言,在顧客點菜之前,與顧客沒有任何的關係,只有顧客點了番茄炒蛋,兩者才發生聯繫,具有相關性。所以,無論兩者中的任何一方出現什麼的問題,都不會影響另一方這種特性體現在軟件工程中,就是可維護性比較好,非常便於進行單元測試,便於調試程序和診斷故障。
代碼中的每一個Class都可以單獨測試,彼此之間互不影響,只要保證自身的功能無誤即可,這就是組件之間低耦合或者無耦合帶來的好處。
第二、番茄炒蛋和顧客的之間無關性,還帶來了另外一個好處,做菜的餐廳和顧客完全可以是互不相干的,他們之間唯一需要遵守的就是菜品質量標準,
這種特性體現在軟件開發過程中,每個開發團隊的成員都只需要關心實現自身的業務邏輯,完全不用去關心其它的人工作進展,因爲你的任務跟別人沒有任何關係,也不用依賴於別人的組件,可以單獨測試,再也不用扯不清責任了。
在一箇中大型項目中,團隊成員分工明確、責任明晰,很容易將一個大的任務劃分爲細小的任務,開發效率和產品質量必將得到大幅度的提高。
第三、餐廳可以把番茄炒蛋可以做給任何喜歡喫的人,可以給小紅,小黃,小藍,等等等。
在軟件工程中,這種特性就是可複用性好,我們可以把具有普遍性的常用組件獨立出來,反覆利用到項目中的其它部分,或者是其它項目,當然這也是面向對象的基本特徵。顯然,IOC不僅更好地貫徹了這個原則,提高了模塊的可複用性。符合接口標準的實現,都可以插接到支持此標準的模塊中。
第四、如果有一天有顧客說,我喜歡喫偏甜的番茄炒蛋,那麼只用在做番茄雞蛋的時候多放糖就行了,改下菜的配方。
在IOC中只要修改配置文件就可以了,也就是把對象生成放在配置文件裏進行定義,這樣,當我們更換一個實現子類將會變得很簡單,只要修改配置文件就可以了,完全具有熱插撥的特性。

缺點
第一、軟件系統中由於引入了第三方IOC容器,生成對象的步驟變得有些複雜,本來是兩者之間的事情,又憑空多出一道手續,所以,我們在剛開始使用IOC框架的時候,會感覺系統變得不太直觀。所以,引入了一個全新的框架,就會增加團隊成員學習和認識的培訓成本,並且在以後的運行維護中,還得讓新加入者具備同樣的知識體系。
第二、由於IOC容器生成對象是通過反射方式,在運行效率上有一定的損耗。如果你要追求運行效率的話,就必須對此進行權衡。
第三、具體到IOC框架產品來講,需要進行大量的配製工作,比較繁瑣,對於一些小的項目而言,客觀上也可能加大一些工作成本。(對於使用IDE重構,如修改類名的時候,XML文件中的類名必須手動修改)
第四、IOC框架產品本身的成熟度需要進行評估,如果引入一個不成熟的IOC框架產品,那麼會影響到整個項目,所以這也是一個隱性的風險。

總結:
關於優缺點部分參考自:傳送門
我們大體可以得出這樣的結論:一些工作量不大的項目或者產品,不太適合使用IOC框架產品。另外,如果團隊成員的知識能力欠缺,對於IOC框架產品缺乏深入的理解,也不要貿然引入。最後,特別強調運行效率的項目或者產品,也不太適合引入IOC框架產品。

三、依賴注入的幾種方式,及優缺點

1、構造函數注入,最常用的注入方式,也是angular和.net core默認的注入方式,

// 代碼來自.Net Core 官網關於依賴注入的教程
public class MyDependency : IMyDependency
{
    private readonly ILogger<MyDependency> _logger;

    public MyDependency(ILogger<MyDependency> logger)
    {
        _logger = logger;
    }

    public Task WriteMessage(string message)
    {
        _logger.LogInformation(
            "MyDependency.WriteMessage called. Message: {Message}", 
            message);

        return Task.FromResult(0);
    }
}
// 使用的前提,必須在Startup.ConfigureServices容器中註冊服務,具體不做描述
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
// 代碼來自Angular官網關於依賴注入的教程
export class UserContextService {
  constructor(private userService: UserService, private loggerService: LoggerService) {
  }
}
// 使用的前提,必須在UserService添加@Injectable() 裝飾器,下面代碼意思是把此服務注入到根module中
@Injectable({
  providedIn: 'root'
})

優點:

  • 在構造方法中體現出對其他類的依賴,一眼就能看出這個類需要其他那些類才能工作。
  • 脫離了IOC框架,這個類仍然可以工作。
  • 一旦對象初始化成功了,這個對象的狀態肯定是正確的。

缺點:

  • 構造函數會有很多參數。
  • 有些類是需要默認構造函數的,比如MVC框架的Controller類,一旦使用構造函數注入,就無法使用默認構造函數。
  • 這個類裏面的有些方法並不需要用到這些依賴。

2、Setter注入
通過屬性的訪問器進行依賴注入

private IMyInterFace _myinterface; 
public IMyInterFace myinterface
{ 
    get { return _myinterface; } 
    set { _myinterface = value; } 
} 

優點:

  • 在對象的整個生命週期內,可以隨時動態的改變依賴,非常靈活。

缺點:

  • 對象在創建後,被設置依賴對象之前這段時間狀態是不對的。
  • 相比構造函數注入,顯得不直觀,無法清晰地表示哪些屬性是必須的。
    3、接口注入,通過接口實現依賴注入
public interface IMyInterFaceCace
{
    IMyInterFace myinterfacce { get; set; }
}

class MyClass : IMyInterFaceCace
{
    private IMyInterFace _myinterfacce;
    public IMyInterFace myinterfacce
    {
        get { return _myinterfacce; }
        set { _myinterfacce = value; }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章