IOC(Inversion of Control) 控制反转,是一种设计原则,意味者将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。控制反转是为了解耦,方便测试和功能复用。由对象主动控制去获取依赖对象,变成由容器创建依赖对象,并注入到对象,对象被动接收依赖对象,即为反转。
IOC Introduction
概念区分
- 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
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
66namespace 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之间的耦合使用抽象实现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
51namespace 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实现依赖注入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
41namespace 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
37namespace 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
52namespace 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容器
使用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容器。
- 接口类型或基本类型的简化类型映射注册
- 支持现有的实例的注册
- 支持基于代码的注册及设计时注册
- 通过构造函数,属性或方法在运行时自动注入注册
- 支持延迟解决方案
- 基于生命周期管理器自动处理实例
- 支持类型拦截和实例拦截
创建控制台应用程序,安装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类型的依赖使用UnityContainer自动注册依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20namespace 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();
}
}
}构造函数注入实现
上述,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
86namespace 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();
}
}
}
属性注入实现
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();
}
}
}方法注入实现
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();
}
}
}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
38namespace 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
37namespace 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
21namespace 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();
}
}
}
最后更新: 2018年09月29日 00:09
原始链接: https://www.github.com/ChangHub/BlogImages/raw/master/2018/09/23/控制反转IOC/