IoC容器Autofac

IoC容器Autofac(2) - 一個簡單示例(附demo源碼)

2013-03-19 18:20 by JustRun, 2608 閱讀, 11 評論, 收藏編輯

上篇文章中(IoC容器Autofac(1) -- 什麼是IoC以及理解爲什麼要使用Ioc),我們用自己的方式實現了一個簡陋的工廠類來實現IoC.

這裏我們嘗試使用Auotfac來替換我們的工廠類MovieFinderFactory.

(Autofac的名字應當取的是非常貼切的,它本質上其實就是一個產出對象的自動工廠)

閱讀目錄:

一. 使用自定義工廠類實現IoC的例子

二. 改造代碼,去除MovieFinderFactory

三. 應用Autofac替代工廠類

四. 當需求發生變動, Autofac如何應對?

五. Autofac對程序架構的影響

六. 總結

 

一、使用自定義工廠類實現IoC的例子

我們回顧一下之前的代碼:

複製代碼
//這個類的作用是篩選出MPG類型的電影
public class MPGMovieLister:IMovieFinder
{
  public Movie[] GetMPG()
  {
       var finder = MovieFinderFactory.GetFinder();//這裏調用工廠類獲取具體的實例,得到一個電影列表
       var allMovies = finder.FindAll();
       return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray();
   }
}
 

public class MovieFinderFactory
{
     public static IMovieFinder GetFinder()
     {
         return new ListMovieFinder();
     }
} 

public class ListMovieFinder :IMovieFinder
{
   public List<Movie> FindAll()
   {
       return new List<Movie>
                  {
                      new Movie
                          {
                              Name = "Die Hard.wmv"
                          },
                      new Movie
                      {
                          Name = "My Name is John.MPG"
                      }
                 };
   }
}

public interface IMovieFinder { List<Movie> FindAll() }
複製代碼

 

這裏MPGMovieLister已經不和具體的MovieFinder耦合了,而是依賴於MovieFinderFactory工廠類提供的IMovieFinder接口的具體實現來取Movie數據。

所以工廠類只要返回不同的實現IMovieFinder的實例,就能夠讓MovieLister從列表,文本,數據庫,web service …… 中獲取數據。

二、改造代碼,去除MovieFinderFactory

在應用Autofac替換MovieFinderFactory之前,我們先從代碼中去掉MovieFinderFactory, 改動之後的代碼是這樣:

複製代碼
public class MPGMovieLister
{
    private readonly IMovieFinder _movieFinder;
    //增加了構造函數,參數是IMovieFinder對象
    public MPGMovieLister(IMovieFinder movieFinder)
    {
         _movieFinder = movieFinder;
    }

    public Movie[] GetMPG()
    {
     var allMovies = _movieFinder.FindAll();
     return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray();
    }
}

public interface IMovieFinder
{
    List<Movie> FindAll()
} 
複製代碼

我們去掉了工廠類MovieFinderFactory, 改造了MPGMovieLister, 添加了一個構造函數, 構造函數要求使用MPGMovieLister時,需要提供一個IMovieFinder的實例。

三、應用Autofac替代工廠類

應用Autofac改造上面的代碼。

第一步: 從Nuget中添加Autofac引用

第二步:

* 創建一個ContainerBuilder對象(ContainerBuilder從字面的意思就是用來創建Container(容器)的,而Conainter就是我們從中取各種我們需要對象的地方)

* 註冊我們後面將從容器中取出對象的類型。

代碼是這樣:

var builder = new ContainerBuilder();//

builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces();//註冊ListMovieFinder類型,這裏的AsImplementedInterfaces表示以接口的形式註冊
builder.RegisterType<MPGMovieLister>();//註冊MPGMovieLister類型

* 創建容器

_container = builder.Build();

 

第三步: 在程序中使用 _container容器:

複製代碼
var lister = _container.Resolve<MPGMovieLister>();

foreach (var movie in lister.GetMPG())
{
     Console.WriteLine(movie.Name);
} 
複製代碼

 

理解一下Autofac爲我們在背後做了什麼:

首先,我們註冊了類型ListMovieFinder和MPGMovieLister,這樣容器就能夠知道如何創建這兩種類型的實例了。(類其實是創建對象的模板,當我們把模板註冊給Autofac, 它就會遵循這個模板爲我們提供實例)

後面的代碼中,我們調用Resolve方法,取出一個MPGMovieLister的實例。

_container.Resolve<MPGMovieLister>();

這裏還有一個需要解釋的,對於MPGMovieLister類型,我們爲Autofac提供了類型, 但是當Autofac創建MPGMovieLister的實例, 調用它的構造函數的時候,卻遇到了問題:

它的構造函數需要提供一個IMovieFinder的實例作爲參數的, 聰明的Autofac要在自己的容器裏找找,看看沒有有辦法提供一個IMovieFinder的實例。

這個時候Autofac會發現我們註冊過ListMovieFinder, 並且通過AsImplementedInterfaces()方法,指明瞭就是爲接口IMovieFinder提供實例的。

所以Autofac會創建一個ListMovieFinder的實例,作爲創建MPGMovieLister時,提供給構造函數的參數。

builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces();

 

四、當需求發生變動, Autofac如何應對?

上面的例子中,我們的類ListMovieFinder實現了IMovieFinder接口, 實際運行中,是由它來提供數據。

假如這個時候,我們要從數據庫中獲取數據,怎麼辦?

非常簡單,創建一個類DBMovieFinder繼承IMovieFinder接口, 然後註冊給Autofac就可以了。 這樣程序就非常容易的切換到從數據庫中取數據了。

註冊相關改動的代碼是這樣的:

複製代碼
var builder = new ContainerBuilder();
builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces();

//這裏註冊了DBMovieFinder, 這個類繼承IMovieFinder接口。因爲它也使用了AsImplementedInterfaces,它會覆蓋ListMovieFinder的註冊。
builder.RegisterType<DBMovieFinder>().AsImplementedInterfaces(); builder.RegisterType<MPGMovieLister>(); 
_container = builder.Build();
複製代碼

 

五、Autofac對程序架構的影響

常見的程序架構大概是: UI層, 業務邏輯層, 持久層(數據層)。

我們可以使用Autofac作爲不同層之間的中間人,讓UI層依賴於業務邏輯層的抽象接口,業務邏輯層依賴於持久層的接口,而實際運行過程中的實例都由Auotfac來提供。

這樣我們就能夠解除不同層之間的依賴,將所有的註冊類型的操作在一個核心函數或者核心類中實現,那麼只要修改這個函數或者類,就能夠非常方便的讓它們之間的依賴關係發生變化。

 

比如, 在一個大的項目中,持久層和業務邏輯層是並行開發的,而且是不同團隊開發,這個時候業務邏輯開發團隊的人在沒有持久層代碼的情況下,如何開始呢?

我們只要定義好持久層的接口, 業務邏輯團隊再寫一些Stub類(樁類)來實現這些接口,讓這些Stub類來替換真正的持久層,所要做的就只是簡單的把這些Stub類型註冊到Autofac中就可以了。同時做業務邏輯層的單元測試也非常容易了。

 

拿上面的例子來說,就是這個樣子:

複製代碼
var builder = new ContainerBuilder();
if(IsLive)//如果是正式環境中,使用DBMovieFinder, 從數據庫中獲取數據
{
    builder.RegisterType<DBMovieFinder>().AsImplementedInterfaces();
}
else//在開發環境中,先用Stub類ListMovieFinder替代
{
    builder.RegisterType<ListMovieFinder>().AsImplementedInterfaces();
}
builder.RegisterType<MPGMovieLister>(); 
_container = builder.Build();
複製代碼

 

同樣的,UI層和業務邏輯層也可以運用同樣的思路。

六、 總結

從上面的例子可以看出,使用IoC對於複雜的項目來說,非常有意義,能夠爲我們搭建一個好的開發層次。

同時,在使用過程中,還能夠發現Autofac有以下優點:

1. 可以使用C#代碼來完成註冊配置,非常方便而且便於調試。(使用xml配置,往往容易出現格式不對,或者其它問題,非常難於調試和排錯)

2. 非常聰明,能夠自動裝配(發現構造函數需要的必須參數的時候,會自己想辦法解決)

 

相關源代碼下載: AutofactDemo.zip

 

相關文章:

IoC容器Autofac(1) -- 什麼是IoC以及理解爲什麼要使用Ioc

IoC容器Autofac(3) - 理解Autofac原理,我實現的部分Autofac功能(附源碼)

IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源碼)

理解爲什麼要使用Ioc

分析Autofac如何實現Controller的Ioc(Inversion of Control)


轉載自:http://www.cnblogs.com/JustRun1983/archive/2013/03/19/2968538.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章