在说依赖注入以前,先了解下什么是接口。html
咱们在学编程的时候都知道,接口的相关规则:(来源百度百科)mysql
不少时候看到这么多的概念,也是云里雾里的。项目中的接口使用也是按照老代码依葫芦画瓢。若是是本身练手的代码或者demo,也是没有使用接口。(给本身的借口就是,我只是作些小的东西,根本就不须要使用接口同样能够跑很溜啊。)sql
接口是什么?(说说我本身的理解,不必定对)数据库
接口就是为了更换一个可能过期或者错误的实现而准备的。就想咱们的电脑,里面就处处都是接口。usb、内存条、硬盘、电池、键盘...等等都是有各自的接口。咱们能够经过硬盘接口换个更大的硬盘或者换个更快的固态硬盘。若是键盘坏了,也能够经过键盘接口买个新的键盘换上去。这就是接口明显的好处。接口也能够理解成你们的约定。约定了特定接口的大小功能等等。编程
那么咱们写代码也是同样,在某些地方可能会常常变更,逻辑会常常修改的地方使用接口约定。下面咱们就用硬盘的接口来作示例吧。oracle
首先定义一个硬盘接口。(一个name属性,一个读一个写的方法)ide
/// <summary> /// 硬盘接口 /// </summary> interface IHardDisk { /// <summary> /// 硬盘的名字属性 /// </summary> string name { get; } /// <summary> /// 读取数据方法 /// </summary> void read(); /// <summary> /// 写数据 /// </summary> void write(string str); }
而后咱们买了一个200G的硬盘,它实现了上面的接口。url
public class HardDisk200 : IHardDisk { public string name { get { return "我是200G硬盘"; } } public void read() { Console.WriteLine("我能够写入数据哦...."); } public void write(string str) { Console.WriteLine(str); } }
在电脑中使用这个硬盘。spa
static void Main(string[] args) { //这里的h就是一个插在接口上的设备 IHardDisk h = new HardDisk200(); h.read(); h.write(h.name + ",我能够写入数据哦"); Console.ReadKey(); }
某天,咱们发现这个硬盘过小了,须要换个1T的。(那样咱们能够存不少不少的电影>_<),那么买吧。code
public class HardDisk1T : IHardDisk { public string name { get { return "我是1T硬盘"; } } public void read() { Console.WriteLine("我能够写入数据哦...."); } public void write(string str) { Console.WriteLine(str); } }
而后怎么使用了?只要在电脑上的接口直接插上新的硬盘就ok了,其余的什么地方都不用改。
这就是使用接口的好处。当某天咱们发现电脑太慢了,咱们能够买个固态硬盘,直接在接口使用的地方换上就能够了,其余地方彻底不用修改。
这样,咱们就能够在不一样时期或不一样状况下灵活更换继承实现了接口的任何对象,而不用修改其它地方的代码。
又或者说,实现了这个接口的设备就是存储设备。(它必定有存也必定能够储,也就是必定能够写入和读出数据。)
在咱们了解了什么是接口以后,咱们接着来讲说今天主要的主题吧。
仍是先从例子入手,且是咱们学过编程都知道的例子,三层。(什么?你不知道什么是三层?那你别看了,先补习了再过来)
咱们先来写个简单的三层伪代码。
DAL:
public class DALMsSqlHelper { public int add(string str) { //...省略具体实现 return 1; } //...省略具体实现,如修改 删除 查询 }
BLL:
public class BLLAddStudent { DALMsSqlHelper mssql = null; public BLLAddStudent() { mssql = new DALMsSqlHelper(); } public int addStudent() { string str = ""; //...省略具体实现 return mssql.add(str); } }
UI:
public class UI { BLLAddStudent s = new BLLAddStudent(); public UI() { s.addStudent(); } }
应该说简单得不能在简单的三层。
就在系统用了一年以后,老板说:”据说oracle很牛逼,大公司都是用的oracle。我们也换上吧。“。 好,那就换吧。
DAL:
public class DALOracleSqlHelper { public int addOracle(string str) { //...省略具体实现 return 1; } //...省略具体实现,如修改 删除 查询 }
显然BLL也要进行修改,由于BLL引用了DAL的查询类。
BLL:
public class BLLAddStudent { DALOracleSqlHelper mssql = null; public BLLAddStudent() { mssql = new DALOracleSqlHelper(); } public int addStudent() { string str = ""; //...省略具体实现 return mssql.addOracle(str); } }
不就换个数据库吗?为什么修改这么大,要是老板哪天又要换回oracle怎么办?这得好好想个办法。
首先,咱们定义一个数据访问的接口。
public interface ISqlHelper { int add();
//...省略具体实现,如修改 删除 查询
}
DAL修改以下:
public class DALMsSqlHelper : ISqlHelper { public int add(string str) { //...省略具体实现 return 1; } //...省略具体实现,如修改 删除 查询 } public class DALOracleSqlHelper : ISqlHelper { public int addOracle(string str) { //...省略具体实现 return 1; } //...省略具体实现,如修改 删除 查询 public int add(string str) { //...省略具体实现 return 1; } }
BLL:
public class BLLAddStudent { ISqlHelper mssql = null; public BLLAddStudent(ISqlHelper sqlhelper) { mssql = sqlhelper; } public int addStudent() { string str = ""; //...省略具体实现 return mssql.add(str); } }
UI:
public class UI { public UI() { ISqlHelper sqlhelper = new DALOracleSqlHelper(); BLLAddStudent s = new BLLAddStudent(sqlhelper); s.addStudent(); } }
若是哪天老板又要换会mssql怎样办。那么仅仅只要修改UI
又过一年以后,由于公司不景气。因此又来需求了。老板:”唉,算了。咱们仍是用mysql吧。免费的,为公司节省点“。那么咱们又要修改了。
首先须要从新写个mysql的实现。
DAL:
public class DALMySqlHelper : ISqlHelper { public int add(string str) { //...省略具体实现 return 1; } //...省略具体实现,如修改 删除 查询 }
UI实现以下:
public class UI { public UI() { ISqlHelper sqlhelper = new DALMySqlHelper(); BLLAddStudent s = new BLLAddStudent(sqlhelper); s.addStudent(); } }
咱们有没有发现。咱们只是在DAL新增了一个mysql的实现和修改了下UI层的接口构造。其中BLL咱们根本就没有动它的。
是的,这样咱们就能够说这里的UI对于BLL来讲就是”依赖注入“,BLL对于UI来讲就是”控制反转“。因此,我以为依赖注入和控制反转是同一个概念,只是立场不一样。
上面,咱们看到了虽然BLL层已经不须要变更就能够新增一个数据源的访问。那么咱们能不能也不修改UI层呢?
这里就能够用到咱们上篇讲的反射了。
而后,无论老板想怎么折腾,我只须要改改配置文件就能够了。甚至都不用动代码。(若是须要新增一个数据源操做,也只要从新实现下,而后改改配置文件)。
本文以同步至《C#基础知识巩固系列》