zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    JS 基于面向对象的 轮播图1
    JS 原型继承的几种方法
    angularJs 自定义服务 provide 与 factory 的区别
    C# 调用JS Eval,高效率
    Linq表连接大全(INNER JOIN、LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN、CROSS JOIN)
    C# LINQ干掉for循环
    C# 彻底搞懂async/await
    .NET中的异步编程——动机和单元测试
    .NET中的异步编程——常见的错误和最佳实践
    C# 实用代码段
  • 原文地址:https://www.cnblogs.com/piwefei/p/10472319.html
Copyright © 2011-2022 走看看