IOC(Inversion of Control) 控制反转,是一种设计原则,意味者将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。控制反转是为了解耦,方便测试和功能复用。由对象主动控制去获取依赖对象,变成由容器创建依赖对象,并注入到对象,对象被动接收依赖对象,即为反转。

IOC Introduction

概念区分

IOC概念.jpg

  • IOC:Inversion of Control:设计原则

IOC是一种设计原则,建议在面向对象设计中反转不同类型的控件,以实现应用程序之间的松散耦合。如果想进行测试驱动开发(TDD),必须使用IOC原则。

  • DIP:Dependency Injection Principle:设计原则

DIP原则有助于实现类之间的松散耦合,DIP与IOC一起使用。

DIP建议高级模块不应该依赖于低级模块,两者都取决于抽象。

  • DI:Dependency Injection:设计模式

DI依赖注入,是一种设计模式,它实现了IOC原则来反转对象的创建。

  • IOC Container:框架

IOC容器是一个管理整个应用程序中自动依赖注入的框架,.NET的IOC容器,如:Unity,Ninject,StructureMap,Autofac等。

IOC区别.jpg

流程控制

IOC流程.jpg

  1. 使用工厂模式实现IOC

    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    namespace IOC
    {
    /// <summary>
    /// 业务逻辑层
    /// </summary>
    public class CustomerBusinessLogic
    {
    DataAccess _dataAccess;

    public CustomerBusinessLogic()
    {
    _dataAccess = new DataAccess();
    }

    public string GetCustomerName(int id)
    {
    return _dataAccess.GetCustomerName(id);
    }
    }
    }

    namespace IOC
    {
    /// <summary>
    /// 数据访问层
    /// </summary>
    public class DataAccess
    {
    public string GetCustomerName(int id)
    {
    return "Customer Name";
    }
    }
    }

    //业务逻辑层CustomerBusinessLogic依赖于数据访问层DataAccess,它们之间就是紧耦合,CustomerBusinessLogic包含DataAccess的引用,创建一个DataAccess对象并管理对象的声明周期
    //使用工厂模式创建DataAccess,实现松散耦合第一步

    namespace IOC
    {
    //工厂模式创建数据访问层
    public class DataAccessFactory
    {
    public static DataAccess GetDataAccessObj()
    {
    return new DataAccess();
    }
    }
    }

    namespace IOC
    {
    /// <summary>
    /// 业务逻辑层
    /// </summary>
    public class CustomerBusinessLogic
    {
    public string GetCustomerName(int id)
    {
    DataAccess _dataAccess = DataAccessFactory.GetDataAccessObj();

    return _dataAccess.GetCustomerName(id);
    }
    }
    }
    //将数据访问层DataAccess的创建由业务逻辑层CustomerBusinessLogic反转到DataAccessFactory,实现BusineesLogic与DataAccess之间的耦合
  2. 使用抽象实现DIP

    • 高级模块不应该依赖于低级模块,两者依赖于抽象
    • 抽象不应该依赖于细节,细节取决于抽象
    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
    45
    46
    47
    48
    49
    50
    51
    namespace IOC
    {
    public interface ICustomerDataAccess
    {
    string GetCustomerName(int id);
    }
    }
    namespace IOC
    {
    public class CustomerDataAccess : ICustomerDataAccess
    {
    public string GetCustomerName(int id)
    {
    return "Customer Name";
    }
    }
    }
    //数据访问层DataAccess依赖于接口

    namespace IOC
    {
    public class DataAccessFactory
    {
    public static ICustomerDataAccess GetCustomerDataAccessObj()
    {
    return new CustomerDataAccess();
    }
    }
    }
    //数据访问层DataAccess控制反转

    namespace IOC
    {
    /// <summary>
    /// 业务逻辑层
    /// </summary>
    public class CustomerBusinessLogic
    {
    ICustomerDataAccess _customerDataAccess;
    public CustomerBusinessLogic()
    {
    _customerDataAccess = DataAccessFactory.GetCustomerDataAccessObj();
    }
    public string GetCustomerName(int id)
    {
    return _customerDataAccess.GetCustomerName(id);
    }
    }
    }
    //业务逻辑层BusinessLogic依赖于接口
    //上述,实现了依赖注入原则DIP
  3. 实现依赖注入DI

    将创建服务类对象的责任分离到客户端类

    依赖注入涉及类:三种

    • Client Class:一个依赖与服务类的客户端类
    • Service Class:一个为客户端提供服务的服务类
    • Injector Class:将服务类对象注入到客户端类

    依赖注入类型:三种

    • Constructor Injection:构造函数注入,注入客户端类的构造函数

      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
      namespace IOC
      {
      /// <summary>
      /// 业务逻辑层
      /// </summary>
      public class CustomerBusinessLogic
      {
      //构造函数注入
      ICustomerDataAccess _dataAccess;
      public CustomerBusinessLogic(ICustomerDataAccess customerDataAccess)
      {
      _dataAccess = customerDataAccess;
      }

      public string GetCustomerName(int id)
      {
      return _dataAccess.GetCustomerName(id);
      }
      }
      }

      namespace IOC
      {
      /// <summary>
      /// 服务层
      /// </summary>
      public class CustomerService
      {
      CustomerBusinessLogic _customerBL;
      public CustomerService()
      {
      _customerBL = new CustomerBusinessLogic(new CustomerDataAccess());
      }

      public string GetCustomerName(int id)
      {
      return _customerBL.GetCustomerName(id);
      }
      }
      }
      //通过构造函数,将数据访问层注入到业务逻辑层,由服务层调用,实现业务逻辑层和数据访问层更松散耦合
    • Property Injection:属性注入,注入客户端类的公共属性

      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
      namespace IOC
      {
      /// <summary>
      /// 业务逻辑层
      /// </summary>
      public class CustomerBusinessLogic
      {
      //属性注入
      public ICustomerDataAccess DataAccess { get; set; }

      public string GetCustomerName(int id)
      {
      return DataAccess.GetCustomerName(id);
      }
      }
      }

      namespace IOC
      {
      /// <summary>
      /// 服务层
      /// </summary>
      public class CustomerService
      {
      CustomerBusinessLogic _customerBL;
      public CustomerService()
      {
      _customerBL = new CustomerBusinessLogic();
      _customerBL.DataAccess = new CustomerDataAccess();
      }

      public string GetCustomerName(int id)
      {
      return _customerBL.GetCustomerName(id);
      }
      }
      }
    • Method Injection:方法注入,客户端类实现一个接口,接口方法提供依赖

      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
      45
      46
      47
      48
      49
      50
      51
      52
      namespace IOC
      {
      public interface IDataAccessDependency
      {
      void SetDependency(ICustomerDataAccess dataAccess);
      }
      }

      namespace IOC
      {
      /// <summary>
      /// 业务逻辑层
      /// </summary>
      public class CustomerBusinessLogic : IDataAccessDependency
      {
      //方法注入
      ICustomerDataAccess _dataAccess;

      public string GetCustomerName(int id)
      {
      return _dataAccess.GetCustomerName(id);
      }

      public void SetDependency(ICustomerDataAccess dataAccess)
      {
      _dataAccess = dataAccess;
      }
      }
      }


      namespace IOC
      {
      /// <summary>
      /// 服务层
      /// </summary>
      public class CustomerService
      {
      CustomerBusinessLogic _customerBL;
      public CustomerService()
      {
      _customerBL = new CustomerBusinessLogic();
      _customerBL.SetDependency(new CustomerDataAccess());
      }

      public string GetCustomerName(int id)
      {
      return _customerBL.GetCustomerName(id);
      }
      }
      }
      //上面通过DI实现DIP及IOC,实际项目中依赖类很多,实现这些模式很耗时,可以使用IOC容器
  4. 使用IOC容器实现耦合

    IOC容器又称DI Container,是一个用于实现自动依赖注入的框架,它管理对象的创建和生命周期,并为类注入依赖项。

    DI生命周期:

    • Register:容器必须知道在遇到特定类型时要实例化的依赖项,一般,包含一些注册类型映射的方法
    • Resolve:使用IOC容器,不需要手动创建对象,容器必须包含一些方法来解析指定的类型
    • Dispose:容器管理依赖对象的生命周期

    常用IOC容器:

    • Unity
    • StructureMap
    • Castle Windsor
    • Ninject
    • Autofac
    • DryIoc
    • Simple Injector
    • Light Inject

Unity Container

Unity Container是一个支持.NET应用程序的开源IOC容器,它是一个轻量可扩展的IOC容器。

  • 接口类型或基本类型的简化类型映射注册
  • 支持现有的实例的注册
  • 支持基于代码的注册及设计时注册
  • 通过构造函数,属性或方法在运行时自动注入注册
  • 支持延迟解决方案
  • 基于生命周期管理器自动处理实例
  • 支持类型拦截和实例拦截
  1. 创建控制台应用程序,安装Unity

    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    //接口定义
    namespace UnityContainer
    {
    //车辆接口类:ICar
    public interface ICar
    {
    int Run();
    }
    }
    //接口实现1
    namespace UnityContainer
    {
    /// <summary>
    /// 接口实现类:宝马
    /// </summary>
    public class BMW : ICar
    {
    private int _miles = 0;
    public int Run()
    {
    return ++_miles;
    }
    }
    }
    //接口实现2
    namespace UnityContainer
    {
    /// <summary>
    /// 接口实现类:福特
    /// </summary>
    public class Ford : ICar
    {
    private int _miles = 0;
    public int Run()
    {
    return ++_miles;
    }
    }
    }
    //接口调用
    namespace UnityContainer
    {
    /// <summary>
    /// 接口调用
    /// </summary>
    public class Driver
    {
    private ICar _car = null;

    public Driver(ICar car)
    {
    _car = car;
    }

    public void RunCar()
    {
    Console.WriteLine("Running {0}-{1} mile", _car.GetType().Name, _car.Run());
    }
    }
    }
    //输出
    namespace UnityContainerTest
    {
    class Program
    {
    static void Main(string[] args)
    {
    Driver driver = new Driver(new BMW());
    driver.RunCar();

    Console.Read();
    }
    }
    }

    //上述,Driver类依赖于ICar接口,创建Driver类时,需要手动注入Car类型的依赖
  2. 使用UnityContainer自动注册依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    namespace UnityContainerTest
    {
    class Program
    {
    static void Main(string[] args)
    {
    //创建UnityContainer实例
    IUnityContainer container = new UnityContainer();
    //注册类型映射--注册多个相同类型的映射,将注入最后一个
    container.RegisterType<ICar, BMW>();
    container.RegisterType<ICar, Ford>();
    //自动注入依赖项
    Driver drv = container.Resolve<Driver>();

    drv.RunCar();

    Console.Read();
    }
    }
    }
  3. 构造函数注入实现

    上述,Resolve()方法默认在解析类型时执行构造函数注入。

    • 多个参数

      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
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      namespace UnityContainerTest
      {
      //车辆接口类:ICar
      public interface ICar
      {
      int Run();
      }
      }

      namespace UnityContainerTest
      {
      /// <summary>
      /// 接口实现类:宝马
      /// </summary>
      public class BMW : ICar
      {
      private int _miles = 0;
      public int Run()
      {
      return ++_miles;
      }
      }
      }

      namespace UnityContainerTest
      {
      public interface ICarKey
      {

      }
      }

      namespace UnityContainerTest
      {
      public class BMWKey : ICarKey
      {
      }
      }


      namespace UnityContainerTest
      {
      /// <summary>
      /// 接口调用
      /// </summary>
      public class Driver
      {
      private ICar _car = null;
      private ICarKey _key = null;
      //多个参数构造
      public Driver(ICar car, ICarKey key)
      {
      _car = car;
      _key = key;
      }

      public void RunCar()
      {
      Console.WriteLine("Running {0}-{1} mile", _car.GetType().Name, _car.Run());
      }
      }
      }


      namespace UnityContainerTest
      {
      class Program
      {
      static void Main(string[] args)
      {
      //创建UnityContainer实例
      IUnityContainer container = new UnityContainer();
      //注册类型映射--将每个参数类型都注册
      container.RegisterType<ICar, BMW>();
      container.RegisterType<ICar, Ford>();
      container.RegisterType<ICarKey, BMWKey>();

      //自动注入依赖项
      Driver drv = container.Resolve<Driver>();

      drv.RunCar();

      Console.Read();
      }
      }
      }
    • 多个构造函数

      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
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      //1.在构造函数上使用[InjectionConstructor]属性注解,指示要用于构造注入的构造函数
      namespace UnityContainerTest
      {
      /// <summary>
      /// 接口调用
      /// </summary>
      public class Driver
      {
      private ICar _car = null;
      private ICarKey _key = null;

      //该构造方法会被调用注入依赖类,创建Driver对象
      [InjectionConstructor]
      public Driver(ICar car)
      {
      _car = car;
      }
      public Driver(ICar car, ICarKey key)
      {
      _car = car;
      _key = key;
      }

      public void RunCar()
      {
      Console.WriteLine("Running {0}-{1} mile", _car.GetType().Name, _car.Run());
      }
      }
      }
      //2.在运行时配置,通过在RegisterType()方法中传递InjectionConstructor实例

      namespace UnityContainerTest
      {
      class Program
      {
      static void Main(string[] args)
      {
      //创建UnityContainer实例
      IUnityContainer container = new UnityContainer();
      //注册类型映射
      //会调用具有一个ICar参数的构造函数
      container.RegisterType<Driver>(new InjectionConstructor(new BMW()));
      //或者
      //container.RegisterType<ICar, BMW>();
      //container.RegisterType<Driver>(new InjectionConstructor(container.Resolve<ICar>()));
      //自动注入依赖项
      Driver drv = container.Resolve<Driver>();

      drv.RunCar();

      Console.Read();
      }
      }
      }
  4. 属性注入实现

    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    //1.在属性上使用[Dependency]属性注解
    namespace UnityContainerTest
    {
    /// <summary>
    /// 接口调用
    /// </summary>
    public class Driver
    {
    //属性自动注入实例化Car,默认时container调用RegisterType注册的最后一个类型
    [Dependency]
    public ICar Car { get; set; }
    //也可以设置名称,指定注册类
    //[Dependency("CHCCar")]
    //public ICar Car { get; set; }

    public void RunCar()
    {
    Console.WriteLine("Running {0}-{1} mile", this.Car.GetType().Name, Car.Run());
    }
    }
    }

    namespace UnityContainerTest
    {
    class Program
    {
    static void Main(string[] args)
    {
    //创建UnityContainer实例
    IUnityContainer container = new UnityContainer();
    //注册类型映射
    container.RegisterType<ICar, BMW>();
    //container.RegisterType<ICar, BMW>("CHCCar");
    container.RegisterType<ICar, Ford>();

    //自动注入依赖项
    Driver drv = container.Resolve<Driver>();

    drv.RunCar();

    Console.Read();
    }
    }
    }

    //2.在运行时配置,RegisterType()方法中是传递InjectionProperty实例
    namespace UnityContainerTest
    {
    class Program
    {
    static void Main(string[] args)
    {
    //创建UnityContainer实例
    IUnityContainer container = new UnityContainer();
    //注册类型映射
    container.RegisterType<Driver>(new InjectionProperty("Car", new BMW()));
    //或者
    //container.RegisterType<ICar, Ford>();
    //container.RegisterType<Driver>(new InjectionProperty("Car", container.Resolve<ICar>()));
    //自动注入依赖项
    Driver drv = container.Resolve<Driver>();

    drv.RunCar();

    Console.Read();
    }
    }
    }
  5. 方法注入实现

    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    //1.通过在方法上使用[InjectionMethod]注解属性
    namespace UnityContainerTest
    {
    /// <summary>
    /// 接口调用
    /// </summary>
    public class Driver
    {
    private ICar _car = null;

    [InjectionMethod]
    public void UseCar(ICar car)
    {
    _car = car;
    }

    public void RunCar()
    {
    Console.WriteLine("Running {0}-{1} mile", _car.GetType().Name, _car.Run());
    }
    }
    }

    namespace UnityContainerTest
    {
    class Program
    {
    static void Main(string[] args)
    {
    //创建UnityContainer实例
    IUnityContainer container = new UnityContainer();
    //注册类型映射
    container.RegisterType<ICar, Ford>();
    //自动注入依赖项
    Driver drv = container.Resolve<Driver>();

    drv.RunCar();

    Console.Read();
    }
    }
    }
    //2.通过运行时配置,在RegisterType()方法中传递InjetionMethod实例
    namespace UnityContainerTest
    {
    class Program
    {
    static void Main(string[] args)
    {
    //创建UnityContainer实例
    IUnityContainer container = new UnityContainer();
    //注册类型映射
    container.RegisterType<Driver>(new InjectionMethod("UseCar", new BMW()));
    //或者
    //container.RegisterType<ICar, Ford>();
    //container.RegisterType<Driver>(new InjectionMethod("UseCar", container.Resolve<ICar>()));

    //自动注入依赖项
    Driver drv = container.Resolve<Driver>();

    drv.RunCar();

    Console.Read();
    }
    }
    }
  6. ResolverOvrride

    Unity容器允许使用ResolverOverride覆盖已注册的类型。ResolverOverride是一个抽象类,提供覆盖注册的实现。

    • ParameterOverride:覆盖构造函数参数

      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
      namespace UnityContainerTest
      {
      /// <summary>
      /// 接口调用
      /// </summary>
      public class Driver
      {
      private ICar _car = null;
      public Driver(ICar car)
      {
      _car = car;
      }
      public void RunCar()
      {
      Console.WriteLine("Running {0}-{1} mile", _car.GetType().Name, _car.Run());
      }
      }
      }
      namespace UnityContainerTest
      {
      class Program
      {
      static void Main(string[] args)
      {
      //创建UnityContainer实例
      IUnityContainer container = new UnityContainer();
      //注册类型映射
      container.RegisterType<ICar, Ford>();//默认注册:Ford
      //自动注入依赖项
      Driver drv = container.Resolve<Driver>();
      drv.RunCar();

      Driver drv2 = container.Resolve<Driver>(new ParameterOverride("car", new BMW()));//重写注册:BMW
      drv2.RunCar();

      Console.Read();
      }
      }
    • PropertyOverride:覆盖指定属性

      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
      namespace UnityContainerTest
      {
      /// <summary>
      /// 接口调用
      /// </summary>
      public class Driver
      {
      public ICar Car { get; set; }

      public void RunCar()
      {
      Console.WriteLine("running {0}-{1} mile", this.Car.GetType().Name, Car.Run());
      }
      }
      }

      namespace UnityContainerTest
      {
      class Program
      {
      static void Main(string[] args)
      {
      //创建UnityContainer实例
      IUnityContainer container = new UnityContainer();
      //注册类型映射
      container.RegisterType<Driver>(new InjectionProperty("Car", new BMW()));
      //自动注入依赖项
      Driver drv = container.Resolve<Driver>();
      drv.RunCar();

      Driver drv2 = container.Resolve<Driver>(new PropertyOverride("Car", new Ford()));
      drv2.RunCar();

      Console.Read();
      }
      }
      }
    • DependencyOverride:覆盖依赖项

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      namespace UnityContainerTest
      {
      class Program
      {
      static void Main(string[] args)
      {
      //创建UnityContainer实例
      IUnityContainer container = new UnityContainer();
      //注册类型映射
      container.RegisterType<ICar, Ford>();
      //自动注入依赖项
      Driver drv = container.Resolve<Driver>();
      drv.RunCar();

      Driver drv3 = container.Resolve<Driver>(new DependencyOverride<ICar>(new BMW()));
      drv3.RunCar();

      Console.Read();
      }
      }
      }
× 请我吃糖~
打赏二维码