Autofac入门示例 - 上 - 备忘录

上一篇搞清楚了Autofac是什么东东后,这篇我们就开始说一下他怎么用,Autofac最大的优点就是他太简单方便了,既可以用配置文件,也可以用代码来装配。

Autofac的装配工作主要是分三步:

  1. 创建一个ContainerBuilder,容器构建器。
  2. 登记服务和组件,就是程序中所用到的实现了指定接口的类。
  3. 注册实例对象,就是把一些实例注册进行,Autofac在用的时候会自已过来拿
  4. 最后生成容器,Autofac会自动的检测依赖关系,然后进行自动装载。
  5. 最最后就是通过构造出来的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 { getset; }
7         public string Title { getset; }
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上了。

明天再写计算器的讲解吧,在下一篇中将使用配置文件来进行注册,而不象本篇完全的代码注册。

posted @ 2011-07-13 22:29  碧玉软件  阅读(517)  评论(0编辑  收藏  举报