1、依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。 依赖倒置原则,它转换了依赖,高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口
2、控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
控制反转(IoC),它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模块的类中直接通过new来获取。在图1的例子我们可以看到,ATM它自身并没有插入具体的银行卡(工行卡、农行卡等等),而是将插卡工作交给人来控制,即我们来决定将插入什么样的银行卡来取钱。
软件设计原则:原则为我们提供指南,它告诉我们什么是对的,什么是错的。它不会告诉我们如何解决问题。它仅仅给出一些准则,以便我们可以设计好的软件,避免不良的设计。一些常见的原则,比如DRY、OCP、DIP等。
软件设计模式:模式是在软件开发过程中总结得出的一些可重用的解决方案,它能解决一些实际的问题。一些常见的模式,比如工厂模式、单例模式等等。
3、依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。
控制反转(IoC)一种重要的方式,就是将依赖对象的创建和绑定转移到被依赖对象类的外部来实现。
依赖注入(DI),它提供一种机制,将需要依赖(低层模块)对象的引用传递给被依赖(高层模块)对象。通过DI,我们可以在Order类(订单类)的外部将SqlServerDal对象(数据库访问类)的引用传递给Order类对象。根据DIP原则,我们知道高层模块不应该依赖于低层模块,两者应该依赖于抽象。那么构造函数的参数应该是一个抽象类型。
方法一:
- 首选,我们需要定义SqlServerDal的抽象类型IDataAccess,并在IDataAccess接口中声明一个Add方法。
public interface IDataAccess { void Add(); }
- 然后在SqlServerDal类中,实现IDataAccess接口。
public class SqlServerDal:IDataAccess { public void Add() { Console.WriteLine("在数据库中添加一条订单!"); } }
- 接下来,我们还需要修改Order类。
public class Order { private IDataAccess _ida;//定义一个私有变量保存抽象 //属性,接受依赖 (也可以构造函数注入) public IDataAccess Ida { set { _ida = value; } get { return _ida; } } public void Add() { _ida.Add(); } }
- OK,我们再来编写一个控制台程序。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DIPTest { class Program { static void Main(string[] args) { SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象 Order order = new Order();//通过构造函数注入依赖
order.Ida = dal;
//给属性赋值
order.Add(); Console.Read(); } } } - 从上面我们可以看出,我们将依赖对象SqlServerDal对象的创建和绑定转移到Order类外部来实现,这样就解除了SqlServerDal和Order类的耦合关系。当我们数据库换成Access数据库时,只需定义一个AccessDal类,然后外部重新绑定依赖,不需要修改Order类内部代码,则可实现Access数据库的操作。
- 定义AccessDal类:
public class AccessDal:IDataAccess { public void Add() { Console.WriteLine("在ACCESS数据库中添加一条记录!"); } }
- 然后在控制台程序中重新绑定依赖关系:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DIPTest { class Program { static void Main(string[] args) { AccessDal dal = new AccessDal();//在外部创建依赖对象 Order order = new Order(dal);//通过构造函数注入依赖 order.Add(); Console.Read(); } } }
方法二:相比构造函数注入和属性注入,接口注入显得有些复杂,使用也不常见。具体思路是先定义一个接口,包含一个设置依赖的方法。然后依赖类,继承并实现这个接口。
- 首先定义一个接口IDAO:
public interface IDependent { void SetDependence(IDataAccess ida);//设置依赖项 }
- 依赖类实现这个接口:
public class Order : IDependent { private IDataAccess _ida;//定义一个私有变量保存抽象 //实现接口(通过构造函数注入) public void SetDependence(IDataAccess ida) { _ida = ida; } public void Add() { _ida.Add(); } }
- 控制台程序通过SetDependence方法传递依赖:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DIPTest { class Program { static void Main(string[] args) { AccessDal dal = new AccessDal();//在外部创建依赖对象 Order order = new Order(); order.SetDependence(dal);//传递依赖 order.Add(); Console.Read(); } } }
IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。