當咱們想閉上眼睛想如何讓咱們的軟件更加可用可維護時,咱們總能想到一個詞:鬆耦合。在這篇文章中,主要講述了模塊間存在的依賴關係,但這種依賴關係違背了依賴倒置原則。在這以後,咱們將討論一種解除軟件依賴關係的設計模式——IoC,以及它的兩種實現方法:依賴注入(DI)和服務定位。最後咱們簡單地列下當前流行的IoC容器工具。html
目錄spring
當一個模塊/類使用另外一個模塊/類,即存在了一種依賴關係。sql
示例場景:數據庫
在這裏,咱們使用銷售系統中保存訂單的場景。好比,咱們當前的需求是將數據保存到SQL Server中。在這裏咱們只關注業務層與數據持久層之間的依賴關係。編程
示例v1:設計模式
public class SQLServerOrderDAL { public void Add() { Console.WriteLine("The order was added in into sql server database."); } } public class OrderManager { public void AddOrder() { SQLServerOrderDAL orderDAL = new SQLServerOrderDAL(); orderDAL.Add(); } } class Program { static void Main(string[] args) { OrderManager orderManager = new OrderManager(); orderManager.AddOrder(); Console.ReadLine(); } }
在這個時候,當公司的牛XX業務人員將這個銷售系統又賣給了另外一家公司,你們都HAPPY。 可是對方公司惟一但願數據保存到ORACLE,由於他們其它的軟件已經購買了ORACLE受權,而且不想再購買SQL SERVER受權。即軟件須要支持數據庫更換,咱們應該如何解決oracle
依賴倒置原則(DIP)異步
高層模塊不該依賴於低層模塊,二者應該依賴於抽象。ide
抽象不不該該依賴於實現,實現應該依賴於抽象。函數
上述示例v1中,OrderManager依賴於OrderDAL. 即高層模塊(OrderManager)直接依賴於實現(OrderDAL), 而不是依賴於抽象。下面咱們爲數據持久層添加一層抽象,讓業務層和數據持久實現層都依賴於抽象。
示例v2:
public interface IOrderDAL { void Add(); } public class OracleOrderDAL:IOrderDAL { public void Add() { Console.WriteLine("The order was added in into oracle database."); } } public class SQLServerOrderDAL:IOrderDAL { public void Add() { Console.WriteLine("The order was added in into sql server database."); } } public class OrderManager { public void AddOrder() { IOrderDAL orderDAL = new OracleOrderDAL(); orderDAL.Add(); } } class Program { static void Main(string[] args) { OrderManager orderManager = new OrderManager(); orderManager.AddOrder(); Console.ReadLine(); } }
程序到這裏,數據訪問層已經添加一層抽象,即業務層和數據持久層都依賴於抽象。可是,注意這裏,依然存在都依賴,即業務層依然要直接依賴於低層的數據持久實現層。當更換數據庫時,會有不少這樣的代碼要更換。你知道我在說什麼的..這仍是太噁心…
文章到這裏了,咱們先說說控制反轉——IoC(Inversion of Control), 網上關於IoC的解釋不少,我比較喜歡這種http://www.cnblogs.com/liuhaorain/p/3747470.html:
它爲相互依賴的組件提供抽象,將依賴(低層模塊)對象的得到交給第三方(系統)來控制,即依賴對象不在被依賴模塊的類中直接經過new來獲取
在多數狀況下,上面的解釋已經夠用了,更廣義一些的解釋我認爲是:
相對於過程式編程中,代碼按順序一步步執行,控制反轉強調的是,將控制權交出,讓第三方來控制程序的執行。
即除了將對象建立的工做交給第三方(咱們主要關心的,如依賴注入和服務定位),IoC應該還包括將流程的控制轉交出去,如事件,Callback 委託,觀察者模式,異步等
在接下來的文章中,咱們主要討論依賴注入和服務定位。
依賴注入DI——Dependence Injection, 是一種IoC的實現方式。即將依賴對象的建立和綁定工做轉移到第三者(調用方)。即 若是A對象依賴於B或C對象,那麼就將B或C對象的建立工做轉到A對象的調用方去。在上面示例中,將OracleOrderDAL或SQLServerOrderDAL的建立工做和綁定到IOrderDAL的工做轉移到OrderManager的調用方中去,即具體對象建立的選擇權移交到更高層的調用方法中。
依賴注入又分構造函數注入,屬性注入和接口注入。我認爲接口注入並很差用,因此這裏只作構造函數和屬性注入的示例。
5.1 構造函數注入
就是經過構造函數,傳遞依賴項。在這裏,經過OrderManager的構造函數傳入SQLServerOrderDAL或OracleOrderDAL
示例v3
public class OrderManager { private IOrderDAL _orderDAL; public OrderManager(IOrderDAL orderDAL) { this._orderDAL = orderDAL; } public void AddOrder() { this._orderDAL.Add(); } } class Program { static void Main(string[] args) { IOrderDAL orderDAL = new SQLServerOrderDAL(); //IOrderDAL orderDAL = new OracleOrderDAL(); OrderManager orderManager = new OrderManager(orderDAL); orderManager.AddOrder(); Console.ReadLine(); } }
5.2 屬性注入
即經過屬性傳入依賴項。在這裏,能過OrderManager的OrderDA屬性項,傳入SQLServerOrderDAL或OracleOrderDAL
示例4
public class OrderManager { private IOrderDAL _orderDAL; public IOrderDAL OrderDAL { set { this._orderDAL = value; } get { return this._orderDAL; } } public void AddOrder() { this._orderDAL.Add(); } } class Program { static void Main(string[] args) { IOrderDAL orderDAL = new SQLServerOrderDAL(); //IOrderDAL orderDAL = new OracleOrderDAL(); OrderManager orderManager = new OrderManager(); orderManager.OrderDAL = orderDAL; orderManager.AddOrder(); Console.ReadLine(); } }
服務定位SL——Service Locator, 也是一種IoC的實現方式。即將依賴對象的建立和綁定工做轉移到第三者(另外一個模塊)。即 若是A對象依賴於B或C對象,那麼就將B或C對象的建立工做轉到F對象中去。在上面示例中,將OracleOrderDAL或SQLServerOrderDAL的建立工做和綁定到IOrderDAL的工做轉移到Factory中去, 即具體對象的建立選擇權移交給Factory中。
示例v5
public class Factory { public static IOrderDAL GetOrderDAL() { //string type = "SQLServer"; string type = "Oracle"; string assemblyName = string.Format("v5_{0}DAL",type); string typeName = string.Format("{0}.{1}OrderDAL",assemblyName,type); return (IOrderDAL)Assembly.Load(assemblyName).CreateInstance(typeName); } } public class OrderManager { public void AddOrder() { IOrderDAL orderDAL = Factory.GetOrderDAL(); orderDAL.Add(); } } class Program { static void Main(string[] args) { OrderManager orderManager = new OrderManager(); orderManager.AddOrder(); Console.ReadLine(); } }
下面是一些主流的IoC容器工具以供參考
1. Unity: http://unity.codeplex.com/
2. Ninject: http://www.ninject.org/
3. Autofac: http://code.google.com/p/autofac/
4. Spring.NET: http://www.springframework.net/
Unity示例v6
public class OrderManager { private IOrderDAL _orderDAL; public OrderManager(IOrderDAL orderDAL) { this._orderDAL = orderDAL; } public void AddOrder() { this._orderDAL.Add(); } } class Program { static void Main(string[] args) { UnityContainer container = new UnityContainer(); //container.RegisterType<IOrderDAL, SQLServerOrderDAL>(); container.RegisterType<IOrderDAL, OracleOrderDAL>(); OrderManager orderManager = container.Resolve<OrderManager>(); orderManager.AddOrder(); Console.ReadLine(); } }
上面是一些我關於IoC和DI的理解,若有不對的地方,歡迎提出討論。
相關連接:
Inversion of Control Containers and the Dependency Injection pattern
Inversion of Control and Dependency Injection: Working with Windsor Container
Dependency Injection (DI) vs. Inversion of Control (IOC)
Inversion of Control – An Introduction with Examples in .NET
Understanding Inversion of Control, Dependency Injection and Service Locator
Dependency Inversion Principle, IoC Container, and Dependency Injection