IoC原理及实现

 

什么是IoC 

IoC是Inversion of Control的缩写,翻译过来为“控制反转”。简单来说,就是将对象的依赖关系交由第三方来控制。在理解这句话之前,我们先来回顾一下IoC的演化。

Ioc前世今生 

传统的new class的方式 
我们写了一个ChineseSpeaker的类,他有一个SayHello的方法并调用输出控制台:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class  Program
        {
            static  void  Main( string [] args)
            {
                ChineseSpeaker chineseSpeaker= new  ChineseSpeaker();
                chineseSpeaker.SayHello();
            }
        }
 
 
        public  class  ChineseSpeaker
        {
            public  void  SayHello()
            {
                Console.WriteLine( "你好!!!" );
            }
        }

上面看起来没有任何问题,一切都很好,但是有一天英国演讲者打招呼的话,我们就需要新建了一个BritishSpeaker类: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class  Program
         {
             static  void  Main( string [] args)
             {
                 //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
                 //chineseSpeaker.SayHello();
 
                 BritishSpeaker britishSpeaker = new  BritishSpeaker();
                 britishSpeaker.SayHello();
             }
         }
 
         public  class  BritishSpeaker
         {
             public  void  SayHello()
             {
                 Console.WriteLine( "Hello!!!" );
             }
         }
 
         //ChineseSpeaker 同上面的代码一样
到目前为止,代码已经暴露出设计原则中要避免的问题:松耦合(loose coupling)。程序中非常依赖实际的class,这导致了: 
当出现“日本人”、“印度人”时,我们不得不修改和重新编译代码。当程序代码和逻辑不复杂的时候问题不大,但当程序变大的时候程序猿就苦逼了。 
Interface方式
为了避免这种直接依赖关系,我们需要把对象或行为抽象出来一个东西,叫做接口(interface)。它就像电脑中的usb插口,无论是优盘还是鼠标只要插头是usb的我就能使用,从而屏蔽了复杂性。 
因此,我们把代码改成: 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  interface  ISpeak
{
     void  SayHello();
}
 
public  class  BritishSpeaker : ISpeak
{
     public  void  SayHello()
     {
         Console.WriteLine( "Hello!!!" );
     }
}
 
 
public  class  ChineseSpeaker : ISpeak
{
     public  void  SayHello()
     {
         Console.WriteLine( "你好!!!" );
     }
}
因为我们现在把类的实现和功能拆出来了,所以我们可以让客户端动态的来选择谁SayHello 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  Program
        {
            static  void  Main( string [] args)
            {
                //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
                //chineseSpeaker.SayHello();
                //BritishSpeaker britishSpeaker = new BritishSpeaker();
                //britishSpeaker.SayHello();
 
                ISpeak speak;
 
                if  (args.Length > 0 && args[0] == "Chinese" )
                {
                    speak = new  ChineseSpeaker();
                }
                else
                {
                    speak = new  BritishSpeaker();
                }
 
                speak.SayHello();
            }
        }

这时候我们不知不觉的用到了面向对象六大原则中的依赖倒转原则(DIP),高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口。 好,让我们回到IoC,比较上面的两种写法:

  • 传统的写法类在定义的瞬间就已经决定具体的类型,他的流程是从上到下的 
  • 使用interface的写法是在实例化时才决定类的具体类型,也就是用到的时候才会new(),他的流程是new后面来控制的 

这时候我们再来看IoC的意思是控制反转,就能大概理解了。传统的写法流程属于从上到下,而interface写法则是由new()其他的类来决定类的实现,因此控制的流程反转了。

DI是什么

利用interface的方式,可以让类在使用的时候再决定由哪个具体类来实现。那该如何实现这种方式呢?这时就有一个新的名称出现了,就是Dependency Injection(依赖注入),简称DI。DI有三种方式,分别是构造函数注入、属性注入、接口注入 
构造函数注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public  class  Printer
       {
           private  ISpeak _speak;
           public  Printer(ISpeak speak) //构造函数注入
           {
               _speak = speak;
           }
       }
 
       class  Program
       {
           static  void  Main( string [] args)
           {
               //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
               //chineseSpeaker.SayHello();
               //BritishSpeaker britishSpeaker = new BritishSpeaker();
               //britishSpeaker.SayHello();
 
               //ISpeak speak;
 
               //if (args.Length > 0 && args[0] == "Chinese")
               //{
               //    speak = new ChineseSpeaker();
               //}
               //else
               //{
               //    speak = new BritishSpeaker();
               //}
 
               //speak.SayHello();
 
               Printer print;
 
               if  (args.Length > 0 && args[0] == "Chinese" )
               {
                   print = new  Printer( new  ChineseSpeaker());
               }
               else
               {
                   print = new  Printer( new  BritishSpeaker());
               }
 
           }
       }


属性注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public  class  Printer
{
     public  ISpeak Speaker { get ; set ; }
}
 
class  Program
{
     static  void  Main( string [] args)
     {
         //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
         //chineseSpeaker.SayHello();
         //BritishSpeaker britishSpeaker = new BritishSpeaker();
         //britishSpeaker.SayHello();
 
         //ISpeak speak;
 
         //if (args.Length > 0 && args[0] == "Chinese")
         //{
         //    speak = new ChineseSpeaker();
         //}
         //else
         //{
         //    speak = new BritishSpeaker();
         //}
 
         //speak.SayHello();
 
         Printer print = new  Printer();
         if  (args.Length > 0 && args[0] == "Chinese" )
         {
             print.Speaker = new  ChineseSpeaker();
         }
         else
         {
             print.Speaker = new  BritishSpeaker();
         }
     }
}

接口注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//接口注入
     public  interface  IPrint
     {
         void  SetSpeaker(ISpeak speak);
     }
 
     public  class  Printer : IPrint
     {
         private  ISpeak _speak;
         public  void  SetSpeaker(ISpeak speak)
         {
             _speak = speak;
         }
     }
 
     class  Program
     {
         static  void  Main( string [] args)
         {
             //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
             //chineseSpeaker.SayHello();
             //BritishSpeaker britishSpeaker = new BritishSpeaker();
             //britishSpeaker.SayHello();
 
             ISpeak speak;
 
             if  (args.Length > 0 && args[0] == "Chinese" )
             {
                 speak = new  ChineseSpeaker();
             }
             else
             {
                 speak = new  BritishSpeaker();
             }
 
             Printer printer = new  Printer();
             printer.SetSpeaker(speak);
         }
     }

IoC与DI的关系

我的理解是IoC是一种理念,DI则是它的具体实现方式

IoC Container

IoC Container帮我们在项目运行时动态的创建实例,它主要功能如下:

  • 动态创建、注入依赖对象 
  • 管理对象生命周期 
  • 映射依赖关系 

IoC Container技术实现的原理就是“反射(Reflection)”。利用反射动态的创建对象,把依赖关系注入到指定对象中。一般常用的注入方式是构造函数注入和属性注入

Service Locator模式

服务定位模式也是IoC理念的一种实现。实现原理:通过ServiceLocator类提供实现IServiceLocator接口的单例,并负责管理已注册实例的创建和访问。通常结合工厂模式来结合使用。 
Service Locator与IoC Container都是IoC的具体实现方式。不同的是Service Locator没有提供管理对象生命周期的功能

.NET 平台下的IoC Container框架

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

Castle Windsor:  http://www.castleproject.org/container/index.html

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

StructureMap: http://docs.structuremap.net/

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

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

什么是IoC 

IoC是Inversion of Control的缩写,翻译过来为“控制反转”。简单来说,就是将对象的依赖关系交由第三方来控制。在理解这句话之前,我们先来回顾一下IoC的演化。

Ioc前世今生 

传统的new class的方式 
我们写了一个ChineseSpeaker的类,他有一个SayHello的方法并调用输出控制台:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class  Program
        {
            static  void  Main( string [] args)
            {
                ChineseSpeaker chineseSpeaker= new  ChineseSpeaker();
                chineseSpeaker.SayHello();
            }
        }
 
 
        public  class  ChineseSpeaker
        {
            public  void  SayHello()
            {
                Console.WriteLine( "你好!!!" );
            }
        }

上面看起来没有任何问题,一切都很好,但是有一天英国演讲者打招呼的话,我们就需要新建了一个BritishSpeaker类: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class  Program
         {
             static  void  Main( string [] args)
             {
                 //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
                 //chineseSpeaker.SayHello();
 
                 BritishSpeaker britishSpeaker = new  BritishSpeaker();
                 britishSpeaker.SayHello();
             }
         }
 
         public  class  BritishSpeaker
         {
             public  void  SayHello()
             {
                 Console.WriteLine( "Hello!!!" );
             }
         }
 
         //ChineseSpeaker 同上面的代码一样
到目前为止,代码已经暴露出设计原则中要避免的问题:松耦合(loose coupling)。程序中非常依赖实际的class,这导致了: 
当出现“日本人”、“印度人”时,我们不得不修改和重新编译代码。当程序代码和逻辑不复杂的时候问题不大,但当程序变大的时候程序猿就苦逼了。 
Interface方式
为了避免这种直接依赖关系,我们需要把对象或行为抽象出来一个东西,叫做接口(interface)。它就像电脑中的usb插口,无论是优盘还是鼠标只要插头是usb的我就能使用,从而屏蔽了复杂性。 
因此,我们把代码改成: 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  interface  ISpeak
{
     void  SayHello();
}
 
public  class  BritishSpeaker : ISpeak
{
     public  void  SayHello()
     {
         Console.WriteLine( "Hello!!!" );
     }
}
 
 
public  class  ChineseSpeaker : ISpeak
{
     public  void  SayHello()
     {
         Console.WriteLine( "你好!!!" );
     }
}
因为我们现在把类的实现和功能拆出来了,所以我们可以让客户端动态的来选择谁SayHello 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  Program
        {
            static  void  Main( string [] args)
            {
                //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
                //chineseSpeaker.SayHello();
                //BritishSpeaker britishSpeaker = new BritishSpeaker();
                //britishSpeaker.SayHello();
 
                ISpeak speak;
 
                if  (args.Length > 0 && args[0] == "Chinese" )
                {
                    speak = new  ChineseSpeaker();
                }
                else
                {
                    speak = new  BritishSpeaker();
                }
 
                speak.SayHello();
            }
        }

这时候我们不知不觉的用到了面向对象六大原则中的依赖倒转原则(DIP),高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口。 好,让我们回到IoC,比较上面的两种写法:

  • 传统的写法类在定义的瞬间就已经决定具体的类型,他的流程是从上到下的 
  • 使用interface的写法是在实例化时才决定类的具体类型,也就是用到的时候才会new(),他的流程是new后面来控制的 

这时候我们再来看IoC的意思是控制反转,就能大概理解了。传统的写法流程属于从上到下,而interface写法则是由new()其他的类来决定类的实现,因此控制的流程反转了。

DI是什么

利用interface的方式,可以让类在使用的时候再决定由哪个具体类来实现。那该如何实现这种方式呢?这时就有一个新的名称出现了,就是Dependency Injection(依赖注入),简称DI。DI有三种方式,分别是构造函数注入、属性注入、接口注入 
构造函数注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public  class  Printer
       {
           private  ISpeak _speak;
           public  Printer(ISpeak speak) //构造函数注入
           {
               _speak = speak;
           }
       }
 
       class  Program
       {
           static  void  Main( string [] args)
           {
               //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
               //chineseSpeaker.SayHello();
               //BritishSpeaker britishSpeaker = new BritishSpeaker();
               //britishSpeaker.SayHello();
 
               //ISpeak speak;
 
               //if (args.Length > 0 && args[0] == "Chinese")
               //{
               //    speak = new ChineseSpeaker();
               //}
               //else
               //{
               //    speak = new BritishSpeaker();
               //}
 
               //speak.SayHello();
 
               Printer print;
 
               if  (args.Length > 0 && args[0] == "Chinese" )
               {
                   print = new  Printer( new  ChineseSpeaker());
               }
               else
               {
                   print = new  Printer( new  BritishSpeaker());
               }
 
           }
       }


属性注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public  class  Printer
{
     public  ISpeak Speaker { get ; set ; }
}
 
class  Program
{
     static  void  Main( string [] args)
     {
         //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
         //chineseSpeaker.SayHello();
         //BritishSpeaker britishSpeaker = new BritishSpeaker();
         //britishSpeaker.SayHello();
 
         //ISpeak speak;
 
         //if (args.Length > 0 && args[0] == "Chinese")
         //{
         //    speak = new ChineseSpeaker();
         //}
         //else
         //{
         //    speak = new BritishSpeaker();
         //}
 
         //speak.SayHello();
 
         Printer print = new  Printer();
         if  (args.Length > 0 && args[0] == "Chinese" )
         {
             print.Speaker = new  ChineseSpeaker();
         }
         else
         {
             print.Speaker = new  BritishSpeaker();
         }
     }
}

接口注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//接口注入
     public  interface  IPrint
     {
         void  SetSpeaker(ISpeak speak);
     }
 
     public  class  Printer : IPrint
     {
         private  ISpeak _speak;
         public  void  SetSpeaker(ISpeak speak)
         {
             _speak = speak;
         }
     }
 
     class  Program
     {
         static  void  Main( string [] args)
         {
             //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
             //chineseSpeaker.SayHello();
             //BritishSpeaker britishSpeaker = new BritishSpeaker();
             //britishSpeaker.SayHello();
 
             ISpeak speak;
 
             if  (args.Length > 0 && args[0] == "Chinese" )
             {
                 speak = new  ChineseSpeaker();
             }
             else
             {
                 speak = new  BritishSpeaker();
             }
 
             Printer printer = new  Printer();
             printer.SetSpeaker(speak);
         }
     }

IoC与DI的关系

我的理解是IoC是一种理念,DI则是它的具体实现方式

IoC Container

IoC Container帮我们在项目运行时动态的创建实例,它主要功能如下:

  • 动态创建、注入依赖对象 
  • 管理对象生命周期 
  • 映射依赖关系 

IoC Container技术实现的原理就是“反射(Reflection)”。利用反射动态的创建对象,把依赖关系注入到指定对象中。一般常用的注入方式是构造函数注入和属性注入

Service Locator模式

服务定位模式也是IoC理念的一种实现。实现原理:通过ServiceLocator类提供实现IServiceLocator接口的单例,并负责管理已注册实例的创建和访问。通常结合工厂模式来结合使用。 
Service Locator与IoC Container都是IoC的具体实现方式。不同的是Service Locator没有提供管理对象生命周期的功能

.NET 平台下的IoC Container框架

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

Castle Windsor:  http://www.castleproject.org/container/index.html

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

StructureMap: http://docs.structuremap.net/

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

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

猜你喜欢

转载自www.cnblogs.com/piwefei/p/10472319.html