Ioc容器Autofac系列(1)-- 初窥

前言

第一次接触Autofac是由于CMS系统--Orchard,后来在一个开源爬虫系统--NCrawler中也碰到过,随着深刻了解,我愈加以为Ioc容器是Web开发中必不可少的利器。那么,Ioc容器是用来作什么的?用了有什么好处?我相信若是不明白这两点就很难敞开心扉接受Ioc容器。html

传统解耦设计的弊端

为方便描述,举个日志的栗子。我简化实现,一个Log类,一个SaveLog方法。若是其余类想拥有记日志功能,那么只需在内部包含一个Log类型的变量:程序员

   public  class  Log
   {
         public  void SaveLog( string message) {
           // save log here.
       }
   }

   public  class  ProductService {
       private  Log _log;
       public ProductService() {
           _log = new Log ();
       }

       public  void SaveProduct() {
           // save product here.
           //...
           _log.SaveLog( "save 1 product" );
       }
   }

有经验的程序员可能会告诉你,这样作会致使其余类与Log耦合。因而,为了解耦,咱们将Log类的功能抽象出来,ILog接口就产生了。如此一来,当其余类须要日志功能时,内含变量就从Log变成了ILog数据库

public  interface  ILog {
         void SaveLog( string message);
     }
     public  class  Log : ILog
     {
         public  void SaveLog( string message)
         {
             // save log here.
         }
     }

     public  class  ProductService
     {
         private  ILog _log;
         public ProductService()
         {
             _log = new Log ();
         }
         // .......
     }

因为ILog被抽象出来,它的实现类可多样化,保存为txt、xml、数据库,甚至可扩展出邮件通知功能等。基本上,我看到的国内项目里,所谓的解耦就只能走到这一步了,但这种设计真的是所谓的“灵活,易扩展,高内聚,低耦合”吗?架构

如今,咱们来模拟需求变动。假设已有TxtLog类把日志保存成txt文件,但使用一段时间后发现:这种日志难以查询。项目经理决定将日志保存到数据库,DbLog类应运而生。可是因为整个系统充斥着new TxtLog(),转换过程实质上就是逐个查找TxtLog替换成DbLog的过程。此时,项目大小决定出错率,出错致使日志记录不全,记录不全致使系统故障后查不到日志,查不到日志致使找不到缘由,找不到缘由致使加班,后果太严重了。框架

突然有天,高潮降临,经理或老板决定换回txt或换另一种日志形式,缘由不明,或节省成本,或体验很差,或佞臣谗言,或成心玩你,或与数据库有世仇,总之--TMD就是要换。因而,悲剧的查找替换再次上演,几番折腾,千疮百孔。函数

而此时此刻,你还会称赞这种设计“灵活,易扩展”吗?post

迈进IoC大门--改变实例化的方式

如今咱们使用Ioc容器--Autofac改进上面的代码,目标是消除代码中的new语句,把实例化类的控制权转移到别的地方,这个地方一般会在一个程序加载时只执行一次的全局方法中。学习

public  class  Global {
     public  static  IContainer container;
     public  void Application_Start() {
         ContainerBuilder builder= new ContainerBuilder ();
         builder.RegisterType< Log >().As< ILog >();
         builder.RegisterType< ProductService >();
         container = builder.Build();
         var productService = container.Resolve< ProductService >();
     }
}

public  class  ProductService
{
     private  ILog _log;
     public ProductService( ILog log)
     {
         _log = log;
     }
     // .......
}

上面代码中,ContainerBuilderIContainer是Autofac中的核心类(以后的文章中会介绍,本文不赘述)。当咱们要实例化一个ProductService时,须要写以下代码:ui

var productService = container.Resolve< ProductService >();

没有任何跟Log有关的操做,但productService中的_log变量确已被赋值了一个Log的实例。Ioc容器会在已注册的组件(类或接口)中匹配实例化参数的类型,一旦发现该类型注册过,则自动将对应的实例赋值给该类型,这个过程叫作--构造函数注入。spa

回头看看那个曾经折磨过咱们的TxtLogDbLog的问题,托Ioc的福,只要在那个全局方法中改一下类型就解决了。

Ioc不单单是控制翻转

也许你会说这个栗子有些极端,实际开发中查找替换的地方并很少,而Ioc只是给实例化换了个地方而已,为了这么一点收益却要付出巨大的学习成本,是否值得?

实际上,Ioc除了控制反转外,还提供了不少对实例生命周期的控制,本文使用的Autofac针对流行的框架(如MVC,WCF)提供了简易整合模块,以及动态代理功能。在不修改原代码的前提下,如何为类中方法添加逻辑?Orchard框架经过Autofac和DynamicProxy库设计出一种颇有意思的架构让两个不相干的类的方法逻辑能合并在一块儿。更多细节,我会在以后的系列文章中向你们展现。

结语

5月,天降陨星,三斤大菠萝来袭,我与基友拔剑而起向邪恶宣战。现在战罢收心,准备踏实写一些文章与你们分享,但愿此次能坚持久一些^_^。

转载于:https://www.cnblogs.com/hkncd/archive/2012/11/21/2780041.html