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

运行后的效果是:

Autofac入门示例 - 上 - 备忘录

看一下官方提供的类的关系图:

Autofac入门示例 - 上 - 备忘录

首先建一个控制台应用程序,工程名为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上了。

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

你可能感兴趣的:(auto)