当咱们想闭上眼睛想如何让咱们的软件更加可用可维护时,咱们总能想到一个词:松耦合。在这篇文章中,主要讲述了模块间存在的依赖关系,但这种依赖关系违背了依赖倒置原则。在这以后,咱们将讨论一种解除软件依赖关系的设计模式——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