實現依賴注入的三種方式


依賴注入(DI)

控制反轉(IoC)一種重要的方式,就是將依賴對象的創建和綁定轉移到被依賴對象類的外部來實現。在上述的實例中,Order類所依賴的對象SqlServerDal的創建和綁定是在Order類內部進行的。事實證明,這種方法並不可取。既然,不能在Order類內部直接綁定依賴關系,那么如何將SqlServerDal對象的引用傳遞給Order類使用呢?

 依賴注入(DI):

它提供一種機制,將需要依賴(低層模塊)對象的引用傳遞給被依賴(高層模塊)對象。通過DI,我們可以在Order類的外部將SqlServerDal對象的引用傳遞給Order類對象。那么具體是如何實現呢?

方法一 構造函數注入

構造函數函數注入,毫無疑問通過構造函數傳遞依賴。因此,構造函數的參數必然用來接收一個依賴對象。那么參數的類型是什么呢?具體依賴對象的類型?還是一個抽象類型?根據DIP原則,我們知道高層模塊不應該依賴於低層模塊,兩者應該依賴於抽象。那么構造函數的參數應該是一個抽象類型。我們再回到上面那個問題,如何將SqlServerDal對象的引用傳遞給Order類使用呢

首選,我們需要定義SqlServerDal的抽象類型IDataAccess,並在IDataAccess接口中聲明一個Add方法。

public interface IDataAccess
{
        void Add();
}

 然后在SqlServerDal類中,實現IDataAccess接口。

復制代碼
public class SqlServerDal:IDataAccess
{
       public void Add()
       {
           Console.WriteLine("在數據庫中添加一條訂單!");
       }
}
復制代碼

 接下來,我們還需要修改Order類。

復制代碼
  public class Order
  {
         private IDataAccess _ida;//定義一個私有變量保存抽象
 
        //構造函數注入
        public Order(IDataAccess ida)
        {
            _ida = ida;//傳遞依賴
        }
 
        public void Add()
        {
            _ida.Add();
        }
}
復制代碼

 OK,我們再來編寫一個控制台程序。

復制代碼
    class Program
    {
        static void Main(string[] args)
        {
            SqlServerDal dal = new SqlServerDal();//在外部創建依賴對象
            Order order = new Order(dal);//通過構造函數注入依賴
 
            order.Add();
 
            Console.Read();
        }
    }
復制代碼

 輸出結果:

從上面我們可以看出,我們將依賴對象SqlServerDal對象的創建和綁定轉移到Order類外部來實現,這樣就解除了SqlServerDal和Order類的耦合關系。當我們數據庫換成Access數據庫時,只需定義一個AccessDal類,然后外部重新綁定依賴,不需要修改Order類內部代碼,則可實現Access數據庫的操作。

定義AccessDal類:

復制代碼
public class AccessDal:IDataAccess
{
        public void Add()
        {
            Console.WriteLine("在ACCESS數據庫中添加一條記錄!");
        }
}
復制代碼

然后在控制台程序中重新綁定依賴關系:

復制代碼
    class Program
    {
        static void Main(string[] args)
        {
             AccessDal dal = new AccessDal();//在外部創建依賴對象
               Order order = new Order(dal);//通過構造函數注入依賴
 
               order.Add();
 
            Console.Read();
        }
    }
復制代碼

輸出結果:

顯然,我們不需要修改Order類的代碼,就完成了Access數據庫的移植,這無疑體現了IoC的精妙。

方法二 屬性注入

顧名思義,屬性注入是通過屬性來傳遞依賴。因此,我們首先需要在依賴類Order中定義一個屬性:

復制代碼
public class Order
{
      private IDataAccess _ida;//定義一個私有變量保存抽象
      
        //屬性,接受依賴
        public IDataAccess Ida
       {
           set { _ida = value; }
           get { return _ida; }
       }
 
       public void Add()
       {
           _ida.Add();
       }
}
復制代碼

 然后在控制台程序中,給屬性賦值,從而傳遞依賴:

復制代碼
    class Program
    {
        static void Main(string[] args)
        {
            AccessDal dal = new AccessDal();//在外部創建依賴對象
            Order order = new Order();
            order.Ida = dal;//給屬性賦值
 
            order.Add();
 
            Console.Read();
        }
    }
復制代碼

我們可以得到上述同樣的結果。

 方法三 接口注入

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

首先定義一個接口: 

public interface IDependent
{
           void SetDependence(IDataAccess ida);//設置依賴項
}

依賴類實現這個接口:

復制代碼
public class Order : IDependent
 {
     private IDataAccess _ida;//定義一個私有變量保存抽象
 
     //實現接口
     public void SetDependence(IDataAccess ida)
     {
         _ida = ida;
     }
 
     public void Add()
     {
         _ida.Add();
     }
 
 }
復制代碼

控制台程序通過SetDependence方法傳遞依賴:

復制代碼
    class Program
    {
        static void Main(string[] args)
        {
            AccessDal dal = new AccessDal();//在外部創建依賴對象
          Order order = new Order();
 
            order.SetDependence(dal);//傳遞依賴
 
            order.Add();
 
            Console.Read();
        }
    }
復制代碼

我們同樣能得到上述的輸出結果。

 雖說上述三種注入形式避免了修改Order類,但仍然避免不了修改控制台輸出的方法。這樣來看,減輕了order類的負擔,但控制台輸出端就必須判斷使用的數據庫,因此:上述三種注入形式的代碼違背了設計模式的開閉原則,仍然有不小的瑕疵,如果解決這個問題呢?

IoC容器

前面所有的例子中,我們都是通過手動的方式來創建依賴對象,並將引用傳遞給被依賴模塊。比如:

SqlServerDal dal = new SqlServerDal();//在外部創建依賴對象
Order order = new Order(dal);//通過構造函數注入依賴

 對於大型項目來說,相互依賴的組件比較多。如果還用手動的方式,自己來創建和注入依賴的話,顯然效率很低,而且往往還會出現不可控的場面。正因如此,IoC容器誕生了。IoC容器實際上是一個DI框架,它能簡化我們的工作量。它包含以下幾個功能:

  • 動態創建、注入依賴對象。
  • 管理對象生命周期。
  • 映射依賴關系。

目前,比較流行的Ioc容器有以下幾種:Ninject、Castle Windsor、Autofac、StructureMap、Unity、Spring.NET、LightInject 等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM