一.前言html
第一次接觸Autofac是由於CMS系統--Orchard,後來在一個開源爬蟲系統--NCrawler中也碰到過,隨着深刻了解,我愈加以爲Ioc容器是Web開發中必不可少的利器。那麼,Ioc容器是用來作什麼的?用了有什麼好處?我相信若是不明白這兩點就很難敞開心扉接受Ioc容器。程序員
二.傳統解耦設計的弊端數據庫
爲方便描述,舉個日誌的栗子。我簡化實現,一個Log類,一個SaveLog方法。若是其餘類想擁有記日誌功能,那麼只需在內部包含一個Log類型的變量:架構
1 public class Log 2 { 3 public void SaveLog(string message) { 4 // save log here. 5 } 6 } 7 8 public class ProductService { 9 private Log _log; 10 public ProductService() { 11 _log = newLog(); 12 } 13 14 public void SaveProduct() { 15 // save product here. 16 //... 17 _log.SaveLog("save 1 product"); 18 } 19 }
有經驗的程序員可能會告訴你,這樣作會致使其餘類與Log耦合。因而,爲了解耦,咱們將Log類的功能抽象出來,ILog接口就產生了。如此一來,當其餘類須要日誌功能時,內含變量就從Log變成了ILog:框架
1 public interface ILog { 2 void SaveLog(string message); 3 } 4 public class Log:ILog 5 { 6 public void SaveLog(string message) 7 { 8 // save log here. 9 } 10 } 11 12 public class ProductService 13 { 14 private ILog _log; 15 public ProductService() 16 { 17 _log = newLog(); 18 } 19 // ....... 20 }
因爲ILog被抽象出來,它的實現類可多樣化,保存爲txt、xml、數據庫,甚至可擴展出郵件通知功能等。基本上,我看到的國內項目裏,所謂的解耦就只能走到這一步了,但這種設計真的是所謂的「靈活,易擴展,高內聚,低耦合」嗎?函數
如今,咱們來模擬需求變動。假設已有TxtLog類把日誌保存成txt文件,但使用一段時間後發現:這種日誌難以查詢。項目經理決定將日誌保存到數據庫,DbLog類應運而生。可是因爲整個系統充斥着new TxtLog(),轉換過程實質上就是逐個查找TxtLog替換成DbLog的過程。此時,項目大小決定出錯率,出錯致使日誌記錄不全,記錄不全致使系統故障後查不到日誌,查不到日誌致使找不到緣由,找不到緣由致使加班,後果太嚴重了。學習
突然有天,高潮降臨,經理或老闆決定換回txt或換另一種日誌形式,緣由不明,或節省成本,或體驗很差,或佞臣讒言,或成心玩你,或與數據庫有世仇,總之--TMD就是要換。因而,悲劇的查找替換再次上演,幾番折騰,千瘡百孔。ui
而此時此刻,你還會稱讚這種設計「靈活,易擴展」嗎?spa
三.邁進IoC大門--改變實例化的方式.net
如今咱們使用Ioc容器--Autofac改進上面的代碼,目標是消除代碼中的new語句,把實例化類的控制權轉移到別的地方,這個地方一般會在一個程序加載時只執行一次的全局方法中。
1 public class Global { 2 public static IContainer container; 3 public void Application_Start() { 4 ContainerBuilder builder=newContainerBuilder(); 5 builder.RegisterType<Log>().As<ILog>(); 6 builder.RegisterType<ProductService>(); 7 container = builder.Build(); 8 var productService = container.Resolve<ProductService>(); 9 } 10 } 11 12 public class ProductService 13 { 14 private ILog _log; 15 public ProductService(ILog log) 16 { 17 _log = log; 18 } 19 // ....... 20 }
上面代碼中,ContainerBuilder和IContainer是Autofac中的核心類(以後的文章中會介紹,本文不贅述)。當咱們要實例化一個ProductService時,須要寫以下代碼:
1 var productService = container.Resolve<ProductService>();
沒有任何跟Log有關的操做,但productService中的_log變量確已被賦值了一個Log的實例。Ioc容器會在已註冊的組件(類或接口)中匹配實例化參數的類型,一旦發現該類型註冊過,則自動將對應的實例賦值給該類型,這個過程叫作--構造函數注入。
回頭看看那個曾經摺磨過咱們的TxtLog換DbLog的問題,託Ioc的福,只要在那個全局方法中改一下類型就解決了。
四.Ioc不單單是控制翻轉
也許你會說這個栗子有些極端,實際開發中查找替換的地方並很少,而Ioc只是給實例化換了個地方而已,爲了這麼一點收益卻要付出巨大的學習成本,是否值得?
實際上,Ioc除了控制反轉外,還提供了不少對實例生命週期的控制,本文使用的Autofac針對流行的框架(如MVC,WCF)提供了簡易整合模塊,以及動態代理功能。在不修改原代碼的前提下,如何爲類中方法添加邏輯?Orchard框架經過Autofac和DynamicProxy庫設計出一種頗有意思的架構讓兩個不相干的類的方法邏輯能合併在一塊兒。更多細節,我會在以後的系列文章中向你們展現。
5月,天降隕星,三斤大菠蘿來襲,我與基友拔劍而起向邪惡宣戰。現在戰罷收心,準備踏實寫一些文章與你們分享,但願此次能堅持久一些^_^。
******************************************************************************
轉載:http://www.cnblogs.com/hkncd/archive/2012/11/21/2780041.html