依賴注入和控制反轉

依賴注入和控制反轉究竟是什麼意思?mysql

控制反轉(Ioc):調用者再也不建立被調用者的實例,由IOC容器框架建立(C#中經常使用的IOC框架有Autofac/Unity等等),這種方式稱爲控制反轉sql

依賴注入(DI):容器框架將建立好的實例注入到調用者稱爲依賴注入數據庫

依賴倒置原則(DIP)編程

高層模塊不該依賴於低層模塊,二者應該依賴於抽象。設計模式

抽象不不該該依賴於實現,實現應該依賴於抽象。框架

使用Ioc的好處是什麼?函數

控制反轉是面向對象編程中的一種設計原則,能夠用來下降代碼之間的耦合度,Ioc把建立和查找依賴對象的控制權交給容器,由容器進行注入,因此對象與對象之間是鬆散耦合,傳統的應用程序都是由咱們在類內部主動建立依賴對象,從而致使類與類之間是緊耦合spa

舉例設計

class SqlDal
{
    public void Add()
    {
        Console.WriteLine("向SQLServer數據庫添加一條新訂單");
    }
}
class Order
{
    SqlDal sqlDal = new SqlDal();

    public void Add()
    {
        sqlDal.Add();
    }
}

首先定義了SqlDal類用於SqlServer數據庫的讀寫操做,再定義Order類負責訂單的邏輯處理,由於訂單數據是要插入到數據庫的,因此在Order類中定了SqlDal類的變量並初始化.這裏Order是依賴於SqlDal類的code

控制檯調用

static void Main(string[] args)
{
    Order order = new Order();
    order.Add();
    Console.ReadKey();
}

這是傳統開發中比較常見的方式,若是這時候數據庫改成了mysql,那麼SqlDal是沒法繼續使用了,須要從新定義mysqlDal,負責mysql數據庫的讀寫操做

class MySqlDal
{
    public void Add()
    {
        Console.WriteLine("向MySql數據庫添加一條新訂單");
    }
}

因爲Order類中直接引用了SqlDal類的對象,因此也須要同步修改成MySqlDal

class Order
{        
    MySqlDal mySqlDal = new MySqlDal();

    public void Add()
    {
        mySqlDal.Add();
    }
}

OK,能夠知足當前需求了,可是若是後期相似的狀況再次出現,就意味着須要將剛纔的操做從新作一次,顯然這不是一個良好的設計,類與類之間是高度耦合的,可擴展性較差,它違背了DIP原則,高層模塊Order不該依賴於底層模塊SqlDal、MySqlDal,二者應該依賴於抽象

改寫代碼

public interface IDal
{
    void Add();
}
class SqlDal : IDal
{
    public void Add()
    {
        Console.WriteLine("向SQLServer數據庫添加一條新訂單");
    }
}
class Order
{
    private IDal _dal;

    /// <summary>
    /// 構造函數注入
    /// </summary>
    /// <param name="dal"></param>
    public Order(IDal dal)
    {
        _dal = dal;
    }
    public void Add()
    {
        _dal.Add();
    }
}

第一步:定義接口IDal,添加方法Add()

第二步:定義SqlDal繼承IDal接口並實現接口中的Add()方法

第三步:在Order類中添加私有變量用於存儲抽象並在構造函數中傳遞具體依賴對象

控制檯調用

static void Main(string[] args)
{
    Order order = new Order(new SqlDal());
    order.Add();
    Console.ReadKey();
}
class MySqlDal : IDal
{
    public void Add()
    {
        Console.WriteLine("向MySql數據庫添加一條新訂單");
    }
}
Order order = new Order(new MySqlDal());
order.Add();

輸出結果是同樣的,可是這裏將依賴對象SqlDal對象的建立和綁定轉移到了Order外部來實現,這就解除了Order與SqlDal類的耦合關係,若是如今出現須要更改數據庫爲MySql的需求,只須要定義MySqlDal類繼承IDal並實現Add()方法,而後外部綁定依賴,不須要修改Order類內部的代碼便可實現替換,很明顯這種方式程序的可擴展性更高

屬性注入

上面所示的方式是在Order類的構造函數中注入依賴對象,還可使用屬性注入的方式,顧名思義,屬性注入是經過屬性來傳遞依賴,所以在Order類中定義一個屬性

class Order
{
    private IDal _dal;

    /// <summary>
    /// 屬性注入
    /// </summary>
    public IDal Dal
    {
        get { return _dal; }
        set { _dal = value; }
    }

public void Add() { _dal.Add(); } }

在控制檯調用時給屬性賦值從而傳遞依賴

static void Main(string[] args)
{          
    Order order = new Order();
    order.Dal = new SqlDal();
    order.Add();            
    Console.ReadKey();
}

接口注入

相比構造函數注入和屬性注入,接口注入顯得有些複雜,使用也不常見。具體思路是先定義一個接口,包含一個設置依賴的方法。而後依賴類,繼承並實現這個接口

public interface IDependent
{
    void SetDepend(IDal idal);
}
class Order: IDependent
{
    private IDal _dal;

    public void Add()
    {
        _dal.Add();
    }

    public void SetDepend(IDal idal)
    {
        _dal = idal;
    }
}

 經過SetDepend方法傳遞依賴

 static void Main(string[] args)
 {
     Order order = new Order();
     order.SetDepend(new SqlDal());
     order.Add();
     Console.ReadKey();
 }

 Ioc容器

前面全部的例子中,咱們都是經過手動的方式來建立依賴對象,並將引用傳遞給被依賴模塊,對於大型項目來講,相互依賴的組件比較多。若是還用手動的方式本身來建立和注入依賴的話,顯然效率很低,並且每每還會出現不可控的場面。正因如此,Ioc容器誕生了。Ioc容器其實是一個DI框架,它能簡化咱們的工做量。它包含如下幾個功能 

  • 動態建立、注入依賴對象
  • 管理對象生命週期
  • 映射依賴關係

總結:DIP是軟件設計的一種思想,Ioc則是基於DIP衍生出的一種軟件設計模式。DI是Ioc的具體實現方式之一,使用最爲普遍。Ioc容器是DI構造函注入的框架,它管理着依賴項的生命週期以及映射關係

相關文章
相關標籤/搜索