我在項目中運用 IOC(依賴注入)--入門篇

以前就聽同事說過依賴注入(dependency injection)、控制反轉(Inversion of Control)。起初聽的是一頭霧水,試着在項目中運用了幾回,總算明白了一些,拋磚引玉,與你們分享一下拙見。數據庫

其實依賴注入和控制反轉指的都是同一個事情。什麼是依賴注入了???架構

【我的理解】app

以最熟悉的三層架構的項目來講,BLL層依賴DAL層,UI層依賴於BLL層,層層之間緊密聯繫。代碼裏處處都是new 對象。認識IOC後,發現IOC最大的好處就是解耦了對這種層級之間的依賴關係進。程序自己不在負責對象的建立和維護,而交給外部容器(IOC容器)來負責。外部容器在運行時動態地將依賴的對象注入到組件之中。函數

簡單的來講就是在類型A中須要使用類型B的實例,而B實例的建立並不禁A來負責,而是經過外部容器來建立。相比以往實例化對象的寫法,確實很爽。工具

以往實例化都是這樣的:this

public class A
{
    public A(B b)
    {
        this.B = b;
    }
 
    public B B { get; set; }
 
    public void Test(B b)
    {
        Console.WriteLine(b.ToString());
    }
}

A 類受B類的影響很大。A類的構造函數中,實例化B,且在A類的Test的方法中,須要判斷B類是否是被實例化。A即建立B又須要維護B。用了IOC,解耦了這種依賴關係。接下來看看我在項目中是怎麼簡單應用的。spa

 

【項目簡單試用】code

一開始用的IOC容器是Unity,四個字,短小精幹(用了有段日子。還有好多功能還需不斷去探索) 。網上還有其它的IOC容器,沒有去了解過(我的認爲,能把一個工具用會,用熟,用精,纔是王道。對象

我把項目中的一段代碼摘出來,項目需求大體上是項目有個數據統計,它下面有三種不一樣的統計類型,須要與數據庫交互,而後展現到頁面。blog

首先須要Unity的類庫,利用VS2012的庫程序包管理工具去下載Unity的類庫。

項目的結構是這樣,標準的是三層架構,BLL和DAL都有接口層IBLL,IDAL。

首先咱們按照不用IOC的方式來實現這個小需求。

IDAL,IBLL 建立接口 IAnalyse 接口裏有個方法

public interface IAnalyse
    {
        /// <summary>
        /// 顯示結果
        /// </summary>
        void ShowResult();
    }

DAL 層引用IDAL,建立類 Analyse.cs 

public class Analyse:IDAL.IAnalyse
    {
        public void ShowResult()
        {
            Console.WriteLine("分析底層數據庫交互");
        }
    }

BLL層引用IDAL,DAL,IBLL 建立 類 Analyse.cs 

        /// <summary>
        /// 顯示結果
        /// </summary>
        public void ShowResult()
        {
            ////之前思路 須要引用IBLL,IDAL,DAL
            IDAL.IAnalyse dal = new DAL.Analyse();
            dal.ShowResult();
        }

 UI層用控制檯應用程序來代替。需引用IBLL,BLL

class Program
    {
        static void Main(string[] args)
        {
            OldMethod();
            Console.ReadKey();
        }

        /// <summary>
        /// 在使用IOC前的寫法。須要引入IBLL,BLL
        /// </summary>
        static void OldMethod()
        {
            IBLL.IAnalyse bll = new BLL.Analyse();
            bll.ShowResult(); 
        }
    }

按照之前的方法,每一個層咱們都在不斷的new 對象。寫到這裏發現這些都是很中規中矩的寫法,之前老師教的也是這樣,可能你會以爲沒啥很差的。我就假如:BLL.Analyse 的構造函數須要參數,參數爲Class B ,去掉無參的構造函數,你是否是全部new 對象的地方都要更改。小項目也許尚未問題,若是是上百萬的大項目咋辦。這就是所謂的層與層之間的耦合度高。(我的拙見,多多指教

接下來咱們用 IOC 來解耦。在Program.cs 增長 IOCMethod1 方法

static void Main(string[] args)
        {
            //OldMethod();
            IOCMethod1();
            Console.ReadKey();
        }

static void IOCMethod1()
        {
            IUnityContainer container=new UnityContainer();
            ////在容器中註冊一種類型,它是一個類型的映射,接口類型是IAnalyse,但願返回的類型是Analyse
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>();
            ////第二種寫法
            //container.RegisterType(typeof (IBLL.IAnalyse), typeof (BLL.Analyse));
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>();
            bll.ShowResult();
        }

使用unity就三步:

第一,new IOC 容器

第二,調用RegisterType 註冊類型。這裏有多種註冊形式。能夠註冊單例的、構造函數有參數的。

第三,調用Resolve 建立對象

認識IOC 簡單吧 O(∩_∩)O

到這,你會發現,UI層 仍然引用了IBLL,BLL,RegisterType方法須要這兩個類庫。既然是解耦,就得解耦完全些。有什麼方法???

我在Core層 DependencyRegister.cs. 創建一個靜態方法,在程序運行開始的時候,註冊全部的類型。UI 層移除BLL ,引用Core 

namespace Core
{
    /// <summary>
    /// 類型註冊
    /// </summary>
    public class DependencyRegister
    {


        public static IUnityContainer DependencyRegisterContainer()
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
                     .RegisterType<IDAL.IAnalyse, DAL.Analyse>();
            return container;
        }
    }
}


////UI層 先移除BLL,引用Core
static void Main(string[] args)
        {
            
            IOCMethod2();
            Console.ReadKey();
        }

static void IOCMethod2()
        {

  IUnityContainer container = DependencyRegister.DependencyRegisterContainer();
IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>(); 
bll.ShowResult();
    }

這樣達到了解耦的目標,如何須要更改類的構造函數,只需更改Core DependencyRegister.cs 就能夠了。

 

【其它解耦方式】

創建core是用了本身得方法來實現解耦的,其實unity還有更以爲,經過配置文件 app.config 來實現。用的是 Microsoft.Practices.Unity.Configuration.dll

    <!-- 程序集-->
    <assembly name="IBLL"/>
    <assembly name="IDAL"/>
    <!--要返回的類型-->
    <alias alias="BLLAnalyse1" type="BLL.Analyse, BLL" />
    <container name="ContainerAnalyse">
      <register type="IBLL.IAnalyse" name="BLLAnalyse1" mapTo="BLLAnalyse1" />
    </container>
private static void IOCMethod3()
        {
            ////經過配置文件註冊全部類型
            IUnityContainer container=new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Configure(container, "ContainerAnalyse");
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>("BLLAnalyse1");
            bll.ShowResult();
        }

 

【投機取巧】

不管是使用全局方法,或者 配置文件,都是註冊類的形式不一樣。每種方法都須要調用Resolve 來建立對象。有沒有連改方法都不用調用的形式。

不用多說,直接上代碼:

 

namespace BLL
{
    public class Analyse:IBLL.IAnalyse
    {
        ////使用依賴注入
        [Dependency]
        public IDAL.IAnalyse dal { get; set; }
        /// <summary>
        /// 顯示結果
        /// </summary>
        public void ShowResult()
        {
            ////之前思路 須要引用IBLL,IDAL,DAL
            //IDAL.IAnalyse dal = new DAL.Analyse();
            
            
            dal.ShowResult();
        }
    }
}

使用[Dependency]屬性。說實話,它的用法還有些沒有弄明白。但願明白這個得多指教指教。

獻醜了,有什麼不對的地方但願你們多多指教。Unity 功能不少,這篇只不過是百裏挑一,還有什麼構造注入,屬性注入、單例的應用。這些,將在下篇繼續分享。但願你們繼續關注,多多指教。

【源碼下載】

相關文章
相關標籤/搜索