天天看點

IoC控制反轉基礎入門1. 簡介2. 控制反轉 IoC3. 依賴倒轉原則 DIP4. 依賴注入DI

文章目錄

  • 1. 簡介
  • 2. 控制反轉 IoC
    • 2.1 概念的了解
    • 2.2 例子說明
  • 3. 依賴倒轉原則 DIP
    • 3.1 定義
    • 3.2 例子
  • 4. 依賴注入DI
    • 4.1 依賴注入的類型
    • 4.2 例子 略

參考:https://www.tutorialsteacher.com/ioc

作者本人在學習Ioc時,始終不了解IoC的本質什麼,很多中文資料在我看來比較難懂,于是搜尋英文資料,終于找到一篇比較淺顯易懂的文章。原文代碼是C#寫的,本人用Java重寫。

1. 簡介

你可能聽說過以下幾個名詞:

中文 英文 英文縮寫
控制反轉 Inversion of Control IoC
依賴倒轉原則 Dependency Inversion Principle DIP
依賴注入 Dependency Injection DI
IoC容器 Ioc Container

但是你可能不清楚他們之間的差別。

IoC控制反轉基礎入門1. 簡介2. 控制反轉 IoC3. 依賴倒轉原則 DIP4. 依賴注入DI

如上圖所示,IoC和DIP是處于上層的設計原則(Principle),也正因為是原則,是以沒有提供具體的實作細節,這些原則是我們設計類時需要遵循的原則。DI是模式(Pattern),Ioc容器是架構(Framework)。

讓我們先簡單過一下上面的幾個概念。

  • 控制反轉 IoC

IoC是一種設計原則,它建議在面向對象設計中反轉(Inversion)各種控制(Control),以達到在類之間的松耦合(Loose Coupling)。在這裡,控制更多指的是類的附加職責,而不是它的主要職責,比如控制應用的流程或控制所依賴類的建立和綁定。

  • 依賴倒轉原則 DIP

DIP同樣可以達到類之間的松耦合,強烈建議同時使用IoC和DIP來達到松耦合設計。

DIP建議高層子產品(high-level modules)不應該依賴低層子產品(low-levle modules),兩者都應該依賴抽象(abstaction, )。在java中,抽象指的是抽象類或者接口。

  • 依賴注入 DI

DI是一種設計模式(Pattern),用來實作IoC,以達到反轉依賴類的建立的目的。

  • IoC容器

IoC容器是一種架構,用來管理應用程式中的自動依賴注入,是以我們程式猿可以節省體力。著名的spring中就提供IoC容器ApplicationContext。

下圖所示,我們一步一步地學習從耦合類到松耦合類的設計過程。

IoC控制反轉基礎入門1. 簡介2. 控制反轉 IoC3. 依賴倒轉原則 DIP4. 依賴注入DI

強耦合類 -> 使用工廠模式實作IoC -> 通過建立抽象實作DIP -> 實作DI -> 使用IoC容器 - > 松耦合類。

2. 控制反轉 IoC

2.1 概念的了解

學習一個東西,首先了解概念。先解釋一下控制反轉的概念,分成控制和反轉兩個部分。

控制:更多指的是控制類的附加職責,而不是它的主要職責,比如控制應用的流程或控制所依賴類的建立和綁定。

反轉:指的将附加職責交給其他類來完成,而不是自己來完成。

比如,你開車去上班,那麼意味着你控制着車,反轉就是你不自己開車,而是坐的士去上班,車的控制權從你的手上轉移到了計程車司機,你就不用操心開車的事,不用操心車停哪裡,不用操心車的保養維修等等,你隻需要關注自己的工作即可。

個人的簡單了解:聚焦于自己主要的職責,把次要的職責外包出去,以此達到類之間松耦合的目的。

2.2 例子說明

public class A {
    private B b;
    public A() {
        b = new B();
    }

    public void task() {
        // do something here
        b.someMethod();
        // do something here
    }
}
public class B {
    public void someMethod() {
        // do something
    }
}
           

如上面的代碼,A調用B類的someMethod()方法,換句話說A依賴于B。A類直接控制B類的建立和生命周期。Ioc原則推薦反轉控制,就是說把B類的建立交給其他類。如下代碼:

public class A {
    private B b;
    public A() {
        b = Factory.getObjectOfB();
    }

    public void task() {
        // do something here
        b.someMethod();
        // do something here
    }
}
public class B {
    public void someMethod() {
        // do something
    }
}

public class Factory {
    public static B getObjectOfB() {
        return new B();
    }
}

           

你可以看到B類的建立已經交給Factory了,A隻需要拿來用就行,專注于自己的主要職責task()方法。這就是控制反轉。

3. 依賴倒轉原則 DIP

3.1 定義

  • 高層子產品不應該依賴底層子產品,兩者都應該依賴抽象;
  • 抽象不應該依賴細節,細節應該依賴抽象。

3.2 例子

public class CustomerBusinessLogic {
    public CustomerBusinessLogic() {
    }
    public String getCustomerName(int id) {
        DataAccess dataAccess = DataAccessFactory.GetDataAccessObj();
        return dataAccess.getCustomerName(id);
    }
}
public class DataAccess {
    public DataAccess() {
    }

    public String getCustomerName(int id) {
        // get it from DB in real app
        return "Dummy Customer Name";
    }
}

public class DataAccessFactory {
    public static DataAccess GetDataAccessObj() {
        return new DataAccess();
    }
}

           

以上的例子,我們用簡單工廠方法實作IoC原則,但是CustomerBusinessLogic直接用DataAccess,還是緊耦合。

正如DIP定義,高層子產品不應該依賴低層子產品,所謂高層子產品就是依賴其他子產品的子產品,例如這裡的CustomerBusinessLogic,那麼被依賴的DataAccess就是低層子產品;另外一個原則是抽象不依賴細節,細節依賴抽象。這裡的抽象是什麼? 在java中,就是抽象類和接口。

public class CustomerBusinessLogic {

    private IDataAccess dataAccess;

    public CustomerBusinessLogic() {
        this.dataAccess = DataAccessFactory.GetDataAccessObj();
    }
    public String getCustomerName(int id) {
        return dataAccess.getCustomerName(id);
    }
}
public interface IDataAccess {
    String getCustomerName(int id);
}
public class DataAccess implements IDataAccess {
    public DataAccess() {
    }

    @Override
    public String getCustomerName(int id) {
        // get it from DB in real app
        return "Dummy Customer Name";
    }
}
public class DataAccessFactory {
    public static IDataAccess GetDataAccessObj() {
        return new DataAccess();
    }
}

           

如上,高層子產品CustomerBusinessLogic和低層子產品DataAccess都依賴于抽象IDataAccess,細節DataAccess依賴于抽象IDataAccess。

4. 依賴注入DI

DI是一種設計模式,使用DI,我們可以将類的建立和綁定在依賴類的外部完成。簡單的說A依賴于B,B的建立和綁定在A類的操作都不在A類内完成,而是其他類中完成。

實作DI涉及到三種類:

  • client class:用戶端類,依賴服務類的類;
  • service class:服務類,給client提供服務的類;
  • injector class:注入類,建立服務類,并且把服務類注入用戶端類的類。
IoC控制反轉基礎入門1. 簡介2. 控制反轉 IoC3. 依賴倒轉原則 DIP4. 依賴注入DI

4.1 依賴注入的類型

有三種方式實作依賴注入:

  • Constructor Injection:構造函數注入;
  • Property Injection:屬性注入,也即setter方法注入;
  • Method Injection:方法注入,

4.2 例子 略