控制反轉IOC的依賴注入方式


引言:

   項目中遇到關於IOC的一些內容,因為和正常的邏輯代碼比較起來,IOC有點反常。因此本文記錄IOC的一些基礎知識,並附有相應的簡單實例,而在實際項目中再復雜的應用也只是在基本應用的基礎上擴展而來的。本文目的兩個,一是記錄學習過程,以便將來溫故;二是請大牛對小弟指點一二。

 

概念:

  控制反轉(Inversion of Control,英文縮寫為IoC)是一個重要的面向對象的法則來削減計算機程序的耦合問題,也是輕量級的Spring框架的核心。 控制反轉一般分為兩種類型,依賴注入(Dependency Injection,簡稱DI)和依賴查找(Dependency Lookup)。依賴注入應用比較廣泛。-百度百科。

 

簡單實例:

下面編寫使用IOC實現的簡單實例,以便大家對IOC有個初始的概念。功能是輸入字符串格式的日志,代碼如下:

接口ILogger和具體的Logger類:

public interface ILogger
    {
        void Log(string msg);
    }

    public class Logger : ILogger
    {
        public virtual void Log(string msg)
        {
            Console.WriteLine("msg is {0}", msg);
        }
    }
View Code

常規的調用方式:

ILogger logger = new Logger();
logger.Log("good");

 

使用IOC模式的客戶端調取方式:

添加using Microsoft.Practices.Unity;

IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, Logger>();
ILogger logger = container.Resolve<ILogger>();
logger.Log("good");

結果如下:

 

介紹常用的概念:依賴、依賴倒置、控制反轉、依賴注入。

日常編碼過程中,新建一個類,進而new對象進而進行相關的業務邏輯,例如下面實例,用戶播放媒體文件:

public class OperationMain
    {
        public void PlayMedia()
        {
            MediaFile _mtype = new MediaFile();
            Player _player = new Player();

            _player.Play(_mtype);
        }
}

    public class Player
    {
        public void Play(MediaFile file)
        {
            Console.WriteLine(file.FilePath);
        }
    }
    public class MediaFile
    {
        public string FilePath { get; set; }
    }
View Code

 

從上文可以看出代碼的耦合度太高了,如果有新的需求,需要改動的地方太多了,那么使用依賴倒置原則來降低耦合度。

依賴倒置原則:

高層模塊不應該依賴於低層模塊,兩者應該依賴於抽象;

抽象不應該依賴於具體,具體應該依賴於抽象;

 public class OperationMain
    {
        public void PlayMedia()
        {
            IMediaFile _mtype = new MediaFile();
            IPlayer _player = new Player();

            _player.Play(_mtype);
        }
    }
    public interface IPlayer
    {
        void Play(IMediaFile file);
    }
    public class Player : IPlayer
    {
        public void Play(IMediaFile file)
        {
            Console.WriteLine(file.FilePath);
        }
    }
    public interface IMediaFile
    {
        string FilePath { get; set; }
    }
    public class MediaFile : IMediaFile
    {
        public string FilePath { get; set; }
    }
View Code

 

控制反轉:

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

控制反轉IoC是Inversion of Control的縮寫,是說對象的控制權進行轉移,轉移到第三方,比如轉移交給了IoC容器,它就是一個創建工廠,你要什么對象,它就給你什么對象,有了IoC容器,依賴關系就變了,原先的依賴關系就沒了,它們都依賴IoC容器了,通過IoC容器來建立它們之間的關系。

 

依賴注入:

依賴注入,控制反轉(IoC)一種重要的方式,就是將依賴對象的創建和綁定轉移到被依賴對象類的外部來實現。

依賴注入,就是由IoC容器在運行期間,動態地將某種依賴關系注入到對象之中。

public class OperationMain
    {
        IMediaFile _mtype;
        IPlayer _player;

        public OperationMain(IPlayer player, IMediaFile mtype)
        {
            _player = player;
            _mtype = mtype;
        }

        public void PlayMedia()
        {
            _player.Play(_mtype);
        }
    }
View Code

調用方式:

static UnityContainer container = new UnityContainer();
        static void init()
        {
            container.RegisterType<IPlayer, Player>();
            container.RegisterType<IMediaFile, MediaFile>();
        }
        static void Main(string[] args)
        {
            init();
            OperationMain op1 = container.Resolve<OperationMain>();
            op1.PlayMedia();
     
            //普通方式
            OperationMain op2 = new OperationMain(new Player(), new MediaFile());
            op2.PlayMedia();
        }
View Code

 

注入方式: 

依賴注入的方式有很多:

  • 構造器注入(Constructor Injection):Ioc容器會智能地選擇選擇和調用適合的構造函數以創建依賴的對象。如果被選擇的構造函數具有相應的參數,Ioc容器在調用構造函數之前解析注冊的依賴關系並自行獲得相應參數對象;
  • 屬性注入(Property Injection):如果需要使用到被依賴對象的某個屬性,在被依賴對象被創建之后,Ioc容器會自動初始化該屬性;
  • 方法注入(Method Injection):如果被依賴對象需要調用某個方法進行相應的初始化,在該對象創建之后,Ioc容器會自動調用該方法

編寫實例說明依賴注入的方式:

接口IA,IB,IC,ID和具體類A,B,C,D。

public interface IA{ }
    public interface IB{}
    public interface IC { }
    public interface ID { }


    public class A : IA
    {
        public IB B { get; set; }
        [Dependency]
        public IC C { get; set; }
        public ID D { get; set; }

        public A(IB b)
        {
            this.B = b;
        }

        [InjectionMethod]
        public void Initialize(ID d)
        {
            this.D = d;
        }
    }

    public class B : IB{}
    public class C : IC { }
    public class D : ID { }
View Code

客戶端調用方式:

IUnityContainer container = new UnityContainer();
            container.RegisterType<IA, A>();
            container.RegisterType<IB, B>();
            container.RegisterType<IC, C>();
            container.RegisterType<ID, D>();
           
            A a = container.Resolve<IA>() as A;
            if (null != a)
            {
                Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No");
                Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No");
                Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No");
            }

運行結果:

 

自我理解:

 依賴注入,從深層次上還是不能理解其本質。此處介紹其用法,大致可分為三步:

1、定義一個container,

IUnityContainer container = new UnityContainer();

2、接口和實現類的注冊,

container.RegisterType<ILogger, Logger>();

3、生成對象

ILogger logger = container.Resolve<ILogger>();

 

 

網上摘抄:

一、

大多數面向對象編程語言,在調用一個類的時候,先要實例化這個類,生成一個對象。
如果你在寫一個類,過程中要調用到很多其它類,甚至這里的其它類,也要“依賴”於更多其它的類,那么可以想象,你要進行多少次實例化。

這就是“依賴”的意思。

依賴注入,全稱是“依賴注入到容器”, 容器(IOC容器)是一個設計模式,它也是個對象,你把某個類(不管有多少依賴關系)放入這個容器中,可以“解析”出這個類的實例。

所以依賴注入就是把有依賴關系的類放入容器(IOC容器)中,然后解析出這個類的實例

二、

假如有一個 船(C)類 ,一個 槳(J) 類,

class C{
    J j = new J() ;
}

如果船要干什么事,肯定需要漿的參與。所以是十分 “依賴”漿;
出了需求需要重構:這時候我們需要控制漿的長度為10在構造方法中。我們需要這么寫;

class C{
    J j = new J(10) ;
}

一個特性需要修改漿構造方法,又需要修改船其中的new J()方法。這時候就設計者就思考,為什么我們加入一個特性需要更改兩個類中代碼(這也就是耦合度高)!
所以我們要解耦要依賴注入;

常用解耦方式:
構造方法注入
如下:我重構代碼的時候在也不用看哪里的漿還是短的了!因為船構造方法依賴了漿。任你漿怎么設計,我用的時候傳一個漿進來即可。(下層依賴上層,用的時候傳入,而不是針對下層去修改)

class C{
    J j ;
    public c(J j)
    {
        this.j = j;
    };
}

工廠模式注入

工廠模式 Human 人 去注入; 工廠類如下

Class Human {
    J j =new J();
    J getJ()
    {
        return j ;
    }
}

此時如下:不管你怎么改漿,改成100米與船都無關,他只要依賴Human,
一千個船修改漿需求我只修改Human類中方法便可。(核心業務邏輯需要依賴的類實例化交給第三方類來實現注入。)

Class C {
    J j ;
    Human h = new Human;
    j=Human.getJ();
}

框架注入(本質還是工廠設計模式的具體實現)
本質也是第三方依賴注入,但是這個第三方可以脫離類。將對象依賴映射信息存儲在容器一般為.xml 或者特定的對象中,並實現動態的注入。

推薦兩篇相當精彩實用的博文:

【調侃】IOC前世今生

IoC模式

談談對Spring IOC的理解

 

引用:

一個簡單的小程序演示Unity的三種依賴注入方式

小菜學習設計模式(五)—控制反轉(Ioc)

IoC模式(依賴、依賴倒置、依賴注入、控制反轉)

IoC模式

 


免責聲明!

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



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