閱讀目錄:
一. 一個沒有使用IoC的例子
二. 當需求發生變動時,非IoC遭遇到的困境
三. 使用IoC徹底解決問題
四. 總結
一、一個沒有使用IoC的例子
IoC的全稱是Inversion of Control,中文叫控制反轉。要理解控制反轉,可以看看非控制反轉的一個例子。
public class MPGMovieLister { public Movie[] GetMPG() { var finder = new ListMovieFinder(); var allMovies = finder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } } public class ListMovieFinder { public List<Movie> FindAll() { return new List<Movie> { new Movie { Name = "Die Hard.wmv" }, new Movie { Name = "My Name is John.MPG" } }; } }
上面的例子中,類MPGMovieLister的作用是列出所有的mpg類型的電影,其中調用了類ListMovieFinder類的方法FindAll()來獲取所有的電影。
這段代碼看起來還不錯,已經符合當前的需求了。
二、當需求發生變動時,非IoC遭遇到的困境
假如,這個時候,movie的列表獲取不是直接創建一個list獲取,而要求從某個文本文件讀取,或者是數據庫獲取,又或者從web service中獲取,我們怎么辦?
第一步,再實現一個類, 比如FileMovieFinder,來實現從文本文件中讀取Movie列表,再把MPGMovieLister中的這行代碼,
var finder = new ListMovieFinder();
替換成
var finder = new FileMovieFinder();
那么這行代碼就又能夠符合要求了。
新的MPGMovieLister代碼是這個樣子:
public class MPGMovieLister { public Movie[] GetMPG() { var finder = new FileMovieFinder(); var allMovies = finder.FindAll(); return allMovies.Where(m => m.Name.EndsWith(".MPG")).ToArray(); } }
如果底層--獲取數據的方式不確定,或者經常更改,MPGMovieLister的代碼豈不是要頻繁改動?
三、使用IoC徹底解決問題:
MPGMovieLister的功能都是依賴着具體的類,ListMovieFinder,FileMovieFinder。當需求發生變化的時候,就會導致MPGMovieLister的代碼也要做相應的改動。
也就是說,MPGMovieLister直接依賴於ListMovieFinder和FileMovieFinder了。
跳出來看,MPGMovieLister的功能只是負責從列表中找出MPG的movie, 至於movie從什么地方來的,不是MPGMovieLister的職責,它也不需要關心。
而解耦合的方法就是”依賴於抽象,而不是依賴於具體”.
(這個例子非常類似於我們的做開發時候的持久層(數據層)和業務邏輯層,其實業務邏輯層也不關心數據是如何提供的,所以業務邏輯層也應當與持久層解耦合。)
實際解決之后的代碼:
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 FileMovieFinder(); } } public interface IMovieFinder { List<Movie> FindAll() }
這里MPGMovieLister就依賴於IMovieFinder接口(依賴抽象), 實際運行時候的實例化由MovieFinderFactory來提供。這樣,不同的Movie數據源只需要一個實現IMovieFinder 的類就可以了,不會對MPGMovieLister產生任何影響。
到這里,實際上已經完成了IoC, 控制權最初取決於MPGMovieLister中是如何實例化MovieFinder 的,現在它已經交出控制權,交由外部來提供具體實例對象了。
這里的MovieFinderFactory就已經是一個簡陋的IoC容器功能了。
四、總結
IoC這種解決依賴的方法是面向對象方法的使用。現實世界中,這種方法無處不在。
比如,汽車不會強依賴於某個品牌的輪胎,任何公司生產的輪胎,只要符合汽車的接口,就可以裝在這個汽車上使用。
還有電腦的USB接口,只要符合USB標准的外設,就都能夠接上電腦使用。
解除依賴不僅讓代碼結構看起來更加合理,其帶來的另一個好處是,各個部分可以單獨的做單元測試,使得單元測試能夠更加容易的進行。這個對於一些復雜度高的項目,對於保證項目的穩定性和可用性非常有意義。
真正的IoC容器比上面的MovieFinderFactory自然要好用和適用的多。下一篇文章將會介紹一個非常棒的IoC框架Autofac.
相關文章:
IoC容器Autofac(3) - 理解Autofac原理,我實現的部分Autofac功能(附源碼)
IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源碼)