IoC和DI的理解

1 概述

當咱們想閉上眼睛想如何讓咱們的軟件更加可用可維護時,咱們總能想到一個詞:鬆耦合。在這篇文章中,主要講述了模塊間存在的依賴關係,但這種依賴關係違背了依賴倒置原則。在這以後,咱們將討論一種解除軟件依賴關係的設計模式——IoC,以及它的兩種實現方法:依賴注入(DI)和服務定位。最後咱們簡單地列下當前流行的IoC容器工具。html

目錄spring

  • 依賴
  • 依賴倒置原則(DIP)
  • 控制反轉IoC:解除兩個模塊間的直接依賴關係
  • 依賴注入(DI)
  • 服務定位(Service Locator)
  • IoC容器

2 依賴

當一個模塊/類使用另外一個模塊/類,即存在了一種依賴關係。sql

示例場景:數據庫

在這裏,咱們使用銷售系統中保存訂單的場景。好比,咱們當前的需求是將數據保存到SQL Server中。在這裏咱們只關注業務層與數據持久層之間的依賴關係。編程

示例v1:設計模式

    public class SQLServerOrderDAL
    {
        public void Add() 
        {
            Console.WriteLine("The order was added in into sql server database.");
        }
    }

    public class OrderManager
    {
        public void AddOrder() 
        {
            SQLServerOrderDAL orderDAL = new SQLServerOrderDAL();
            orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OrderManager orderManager = new OrderManager();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

3 依賴倒置原則(DIP)

在這個時候,當公司的牛XX業務人員將這個銷售系統又賣給了另外一家公司,你們都HAPPY。 可是對方公司惟一但願數據保存到ORACLE,由於他們其它的軟件已經購買了ORACLE受權,而且不想再購買SQL SERVER受權。即軟件須要支持數據庫更換,咱們應該如何解決oracle

依賴倒置原則(DIP)異步

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

抽象不不該該依賴於實現,實現應該依賴於抽象。函數

 

上述示例v1中,OrderManager依賴於OrderDAL. 即高層模塊(OrderManager)直接依賴於實現(OrderDAL), 而不是依賴於抽象。下面咱們爲數據持久層添加一層抽象,讓業務層和數據持久實現層都依賴於抽象。

示例v2:

    public interface IOrderDAL
    {
        void Add();
    }

    public class OracleOrderDAL:IOrderDAL
    {
        public void Add()
        {
            Console.WriteLine("The order was added in into oracle database.");
        }
    }

    public class SQLServerOrderDAL:IOrderDAL
    {
        public void Add()
        {
            Console.WriteLine("The order was added in into sql server database.");
        }
    }

    public class OrderManager
    {
        public void AddOrder() 
        {
            IOrderDAL orderDAL = new OracleOrderDAL();
            orderDAL.Add();
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            OrderManager orderManager = new OrderManager();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

 

4 控制反轉IoC

程序到這裏,數據訪問層已經添加一層抽象,即業務層和數據持久層都依賴於抽象。可是,注意這裏,依然存在都依賴,即業務層依然要直接依賴於低層的數據持久實現層。當更換數據庫時,會有不少這樣的代碼要更換。你知道我在說什麼的..這仍是太噁心…

文章到這裏了,咱們先說說控制反轉——IoC(Inversion of Control), 網上關於IoC的解釋不少,我比較喜歡這種http://www.cnblogs.com/liuhaorain/p/3747470.html:

它爲相互依賴的組件提供抽象,將依賴(低層模塊)對象的得到交給第三方(系統)來控制即依賴對象不在被依賴模塊的類中直接經過new來獲取

 

在多數狀況下,上面的解釋已經夠用了,更廣義一些的解釋我認爲是:

相對於過程式編程中,代碼按順序一步步執行,控制反轉強調的是,將控制權交出,讓第三方來控制程序的執行。

即除了將對象建立的工做交給第三方(咱們主要關心的,如依賴注入和服務定位),IoC應該還包括將流程的控制轉交出去,如事件,Callback 委託,觀察者模式,異步等

在接下來的文章中,咱們主要討論依賴注入和服務定位。

5 依賴注入(DI)

依賴注入DI——Dependence Injection, 是一種IoC的實現方式。即將依賴對象的建立和綁定工做轉移到第三者(調用方)。即 若是A對象依賴於B或C對象,那麼就將B或C對象的建立工做轉到A對象的調用方去。在上面示例中,將OracleOrderDAL或SQLServerOrderDAL的建立工做和綁定到IOrderDAL的工做轉移到OrderManager的調用方中去,即具體對象建立的選擇權移交到更高層的調用方法中。

依賴注入又分構造函數注入,屬性注入和接口注入。我認爲接口注入並很差用,因此這裏只作構造函數和屬性注入的示例。

5.1 構造函數注入

就是經過構造函數,傳遞依賴項。在這裏,經過OrderManager的構造函數傳入SQLServerOrderDAL或OracleOrderDAL

示例v3

    public class OrderManager
    {
        private IOrderDAL _orderDAL;

        public OrderManager(IOrderDAL orderDAL)
        {
            this._orderDAL = orderDAL;
        }

        public void AddOrder()
        {

            this._orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IOrderDAL orderDAL = new SQLServerOrderDAL();
            //IOrderDAL orderDAL = new OracleOrderDAL();
           
            OrderManager orderManager = new OrderManager(orderDAL);
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

5.2 屬性注入

即經過屬性傳入依賴項。在這裏,能過OrderManager的OrderDA屬性項,傳入SQLServerOrderDAL或OracleOrderDAL

示例4

    public class OrderManager
    {
        private IOrderDAL _orderDAL;

        public IOrderDAL OrderDAL 
        {
            set { this._orderDAL = value; }
            get { return this._orderDAL; }
        }

        public void AddOrder() 
        {

            this._orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IOrderDAL orderDAL = new SQLServerOrderDAL();
            //IOrderDAL orderDAL = new OracleOrderDAL();
           
            OrderManager orderManager = new OrderManager();
            orderManager.OrderDAL = orderDAL;
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

6 服務定位(Service Locator)

服務定位SL——Service Locator, 也是一種IoC的實現方式。即將依賴對象的建立和綁定工做轉移到第三者(另外一個模塊)。即 若是A對象依賴於B或C對象,那麼就將B或C對象的建立工做轉到F對象中去。在上面示例中,將OracleOrderDAL或SQLServerOrderDAL的建立工做和綁定到IOrderDAL的工做轉移到Factory中去, 即具體對象的建立選擇權移交給Factory中。

示例v5

    public class Factory
    {
        public static IOrderDAL GetOrderDAL() 
        {
            //string type = "SQLServer";
            string type = "Oracle";
            string assemblyName = string.Format("v5_{0}DAL",type);
            string typeName = string.Format("{0}.{1}OrderDAL",assemblyName,type);
            return (IOrderDAL)Assembly.Load(assemblyName).CreateInstance(typeName);
        }
    }

    public class OrderManager
    {
        public void AddOrder() 
        {
            IOrderDAL orderDAL = Factory.GetOrderDAL();
            orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OrderManager orderManager = new OrderManager();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

7 IoC容器

下面是一些主流的IoC容器工具以供參考

1. Unity:  http://unity.codeplex.com/

2. Ninject:  http://www.ninject.org/

3. Autofac:  http://code.google.com/p/autofac/

4. Spring.NET: http://www.springframework.net/

Unity示例v6

    public class OrderManager
    {
        private IOrderDAL _orderDAL;

        public OrderManager(IOrderDAL orderDAL)
        {
            this._orderDAL = orderDAL;
        }

        public void AddOrder()
        {

            this._orderDAL.Add();
        }
    }

    class Program
    {
        
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            //container.RegisterType<IOrderDAL, SQLServerOrderDAL>();
            container.RegisterType<IOrderDAL, OracleOrderDAL>();

            OrderManager orderManager = container.Resolve<OrderManager>();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

上面是一些我關於IoC和DI的理解,若有不對的地方,歡迎提出討論。

 

相關連接:

Inversion of Control Containers and the Dependency Injection pattern

Inversion of Control and Dependency Injection: Working with Windsor Container

Dependency Injection (DI) vs. Inversion of Control (IOC)
Inversion of Control – An Introduction with Examples in .NET

Understanding Inversion of Control, Dependency Injection and Service Locator

Dependency Injection

Dependency Inversion Principle, IoC Container, and Dependency Injection

Unity Container Introduced by MSDN

相關文章
相關標籤/搜索