上一篇搞清楚了Autofac是什么东东后,这篇我们就开始说一下他怎么用,Autofac最大的优点就是他太简单方便了,既可以用配置文件,也可以用代码来装配。
Autofac的装配工作主要是分三步:
- 创建一个ContainerBuilder,容器构建器。
- 登记服务和组件,就是程序中所用到的实现了指定接口的类。
- 注册实例对象,就是把一些实例注册进行,Autofac在用的时候会自已过来拿
- 最后生成容器,Autofac会自动的检测依赖关系,然后进行自动装载。
- 最最后就是通过构造出来的IContainer取对象实例了。
弄清楚了步骤现在就看一下官方所给出的示例,范例有两个,一个是备忘录程序,一个是计算器(让我想起了曾经的一个面试题),现在先从备忘录开始吧,原文是英文的,如果英语好的同志直接看原版,英文一般的同志可以听我接下来的唠叨。
原文:http://www.codeproject.com/KB/architecture/di-with-autofac.aspx (英文)
源程序:http://www.codeproject.com/KB/architecture/di-with-autofac/autofac-example.zip
运行后的效果是:
看一下官方提供的类的关系图:
首先建一个控制台应用程序,工程名为Remember。偷个懒不截图了,大家都明白吧。现在展示一下这几个核心类是什么样以及它们的功能。
从上面的类图中我们可以粗略的看出,有一个Memo的类,当然它就是我们的主角(备忘录实体)
View Code
1
namespace
Remember
2
{
3
using
System;
4
public
class
Memo
5
{
6
public
DateTime DueAt {
get
;
set
; }
7
public
string
Title {
get
;
set
; }
8
}
9
}
MemoChecker顾名思意就是备忘录检查器,它是用来处理备忘录的工作者。
View Code
1
namespace
Remember
2
{
3
using
System;
4
using
System.Linq;
5
6
class
MemoChecker
7
{
8
IQueryable
<
Memo
>
_memos;
9
IMemoDueNotifier _notifier;
10
11
public
MemoChecker(IQueryable
<
Memo
>
memos, IMemoDueNotifier notifier)
12
{
13
this
._memos
=
memos;
14
this
._notifier
=
notifier;
15
}
16
17
public
void
CheckNow()
18
{
19
var overdueMemos
=
_memos.Where(
20
memo
=>
memo.DueAt
<
DateTime.Now);
21
22
foreach
(var memo
in
overdueMemos)
23
_notifier.MemoIsDue(memo);
24
}
25
}
26
}
还有一个接口IMemoDueNotifier,它是提醒者,该接口被备忘录检查器调用,以便在检查到过期的备忘录实体时提示。
View Code
1
namespace
Remember
2
{
3
interface
IMemoDueNotifier
4
{
5
void
MemoIsDue(Memo memo);
6
}
7
}
具体的提示方式则是由实现了IMemoDueNotifier的具体类来完成的,它们之间的契约是必须继承了TextWriter的类对能作为输出源(比如Console.Out输出到屏幕,StringWriter输出到字符串中,HttpWriter输出到Response.Write流等等),在该示例中实现了PrintingNotifier类来向屏幕中输出过期的备忘录实体。
View Code
1
namespace
Remember
2
{
3
using
System.IO;
4
public
class
PrintingNotifier : IMemoDueNotifier
5
{
6
TextWriter _writer;
7
public
PrintingNotifier(TextWriter writer)
8
{
9
_writer
=
writer;
10
}
11
12
public
void
MemoIsDue(Memo memo)
13
{
14
_writer.WriteLine(
"
Memo '{0}' is due!
"
, memo.Title);
15
}
16
}
17
}
这些类都很简单,建议同志们打开VS,引入Autofac然后自己亲自在电脑上敲一遍可以加深印象。而不仅仅时看一遍就过去了,很容易忘记的。
好了现在我们把刚刚那几个类已经将这些东东都完成了,但是它们还不能一起配合着干起活来。
最后看一下主程序的代码吧,在这里我们将把这些类都组织起来让他们一起工作。在这里我写了一种传统的直接new的方式,也写了使用Autofac的方式,两个方式运行出来的结果是一样的。但是我们通过Autofac注册的方式来处理系统中的所有类和接口(也称组件和服务)时,它们变得很离散,之间都没有耦合,我们需要什么对象时只需要象本示例中一样调用container.Resolve<MemoChecker>() 这个Resolve方法既可。这样我们就可以灵活的替换多个类。
View Code
1
namespace
Remember
2
{
3
using
System;
4
using
System.IO;
5
using
System.Linq;
6
using
Autofac;
7
8
class
Program
9
{
10
static
IQueryable
<
Memo
>
memos
=
new
[]{
11
new
Memo{ Title
=
"
Release Autofac 1.0
"
, DueAt
=
new
DateTime(
2007
,
12
,
14
)},
12
new
Memo{ Title
=
"
Write CodeProject Article
"
, DueAt
=
DateTime.Now},
13
new
Memo{ Title
=
"
Release Autofac 2.3
"
, DueAt
=
new
DateTime(
2010
,
07
,
01
)}
14
}.AsQueryable();
15
16
static
void
Main(
string
[] args)
17
{
18
/*
19
* 以传统的依赖高度耦合的方式创建对象,
20
IMemoDueNotifier memoDueNotifier = new PrintingNotifier(Console.Out);
21
MemoChecker chechker = new MemoChecker(memos, memoDueNotifier);
22
chechker.CheckNow();
23
*/
24
25
//
以IoC依赖注入方式创建对象
26
using
(var container
=
RegisterContainer())
27
container.Resolve
<
MemoChecker
>
().CheckNow();
28
29
Console.ReadKey();
30
}
31
32
///
<summary>
33
///
注册组件容器
34
///
</summary>
35
///
<returns></returns>
36
private
static
IContainer RegisterContainer()
37
{
38
39
//
使用了 Autofac 的依赖注入后的方式
40
//
创建构造器
41
var builder
=
new
ContainerBuilder();
42
43
//
登记MemoChecker组件
44
builder.Register(c
=>
new
MemoChecker(
45
c.Resolve
<
IQueryable
<
Memo
>>
(),
46
c.Resolve
<
IMemoDueNotifier
>
())
47
);
48
49
//
登记PrintingNotifier组件
50
builder.Register(c
=>
new
PrintingNotifier(
51
c.Resolve
<
TextWriter
>
())
52
).As
<
IMemoDueNotifier
>
();
53
54
//
注册实例对象
55
builder.RegisterInstance(memos);
56
builder.RegisterInstance(Console.Out).As
<
TextWriter
>
().ExternallyOwned();
57
58
//
检查依赖关系生成容器
59
return
builder.Build();
60
}
61
}
62
}
完成了上面这个范例你有些茫然,为什么我们要用如此复杂的方式来获取对象呢?它为我们带来了什么便利呢?这个问题很纠结(其实我第一看设计模式的时候也有这种问题)。
引用官方的一段话:
IoC带给了我们一种新的方式解藕在客户代码中直接new的对象,同时它遵循面向接口编程的OO原理,让我们对接口操作而不对具体实现操作,当我们面对程序的变化的时候,就可以增加新的类,然后注册到系统中,而无须修改原来的类和客户代码中所有对该类的引用,这同时也符合了开闭原则。
说了这么多官话,简单的来说就是让我们不需要在程序发生变化的时候,查找每个引用,然后Ctrl+V,Ctrl+C的重复替换,同样我们也可以动态的改变程序的具体实现方式,就拿我们这个例子来说,我们可以实现个继承自IMemoDueNotifier接口的ASP.NET 通知者,这样我们就可以将结果输出到WEB上了。
明天再写计算器的讲解吧,在下一篇中将使用配置文件来进行注册,而不象本篇完全的代码注册。