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

fqyb張繼發表於2015-06-07

上篇文章中(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. 非常聰明,能夠自動裝配(發現建構函式需要的必須引數的時候,會自己想辦法解決)

程式碼地址

http://download.csdn.net/detail/zj735539703/8781515

相關文章