在說依賴注入以前,先了解下什麼是接口。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#基礎知識鞏固系列》