IoC容器Autofac之實例優化(三)

回顧以前的代碼數據庫

//這個類的做用是篩選出MPG類型的電影
public class MPGMovieLister
{
  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() }

2、改造代碼,去除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的實例函數

3、應用Autofac替代工廠類

應用Autofac改造上面的代碼。單元測試

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

第二步:ui

* 建立一個ContainerBuilder對象(ContainerBuilder從字面的意思就是用來建立Container(容器)的,而Conainter就是咱們從中取各類咱們須要對象的地方)spa

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

代碼是這樣:code

var builder = new ContainerBuilder();
builder.RegisterType<ListMovieFinder>().As<IMovieFinder>();//註冊ListMovieFinder類型
builder.RegisterType<MPGMovieLister>();//註冊MPGMovieLister類型

* 建立容器xml

_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();

4、當需求發生變更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();

5、Autofac對程序架構的影響

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

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

這樣就可以解除不一樣層之間的依賴,將全部的註冊類型的操做在一個核心函數或者核心類中實現,那麼只要修改這個函數或者類就可以很是方便的讓它們之間的依賴關係發生變化。

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

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

6、 總結

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

同時,在使用過程當中,還可以發現Autofac有如下優勢:

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

2. 很是聰明,可以自動裝配(發現構造函數須要的必須參數的時候,會本身想辦法解決)

相關文章
相關標籤/搜索