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


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

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

【個人理解】

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

簡單的來說就是在類型A中需要使用類型B的實例,而B實例的創建並不由A來負責,而是通過外部容器來創建。相比以往實例化對象的寫法,確實很爽。

以往實例化都是這樣的:

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,解耦了這種依賴關系。接下來看看我在項目中是怎么簡單應用的。

 

【項目簡單試用】

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

我把項目中的一段代碼摘出來,項目需求大致上是項目有個數據統計,它下面有三種不同的統計類型,需要與數據庫交互,然后展示到頁面。

首先需要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 功能很多,這篇只不過是鳳毛麟角,還有什么構造注入,屬性注入、單例的應用。這些,將在下篇繼續分享。希望大家繼續關注,多多指教。

【源碼下載】


免責聲明!

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



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