什么是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 同上面的代码一样
|
当出现“日本人”、“印度人”时,我们不得不修改和重新编译代码。当程序代码和逻辑不复杂的时候问题不大,但当程序变大的时候程序猿就苦逼了。
Interface方式
因此,我们把代码改成:
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(
"你好!!!"
);
}
}
|
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 同上面的代码一样
|
当出现“日本人”、“印度人”时,我们不得不修改和重新编译代码。当程序代码和逻辑不复杂的时候问题不大,但当程序变大的时候程序猿就苦逼了。
Interface方式
因此,我们把代码改成:
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(
"你好!!!"
);
}
}
|
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/