從前有一個這樣的業務
代碼編號01 需求:在MSSQLServer數據庫中添加訂單信息
step 1 構建MSSQLServer環境,有添加功能
public class MSSQLServer
{
public void Insert(){...}
}
setp 2 構建訂單服務,向MSSQLServer環境添加數據
public class OrderService
{
private MSSQLServer _mssqlServer;
public Order(MSSQLServer mssqlServer)
{
_mssqlServer = mssqlServer;
}
public void Add()
{
_mssqlServer.Insert();
}
}
setp 3 整體貫通,實現需求
static void Main()
{
var mssqlServer= new MSSQLServer();
var orderService = new OrderService(mssqlServer);
orderService.Insert();
}
一個呆萌的員工是這樣擴展的
代碼編號02 需求變更:改用MySql存儲訂單信息
step 1 構建MySql環境,有添加功能
public class MySql
{
public void Insert(){...}
}
setp 2 改造訂單服務,向MySql環境添加數據
public class OrderService
{
private MSSQLServer _mssqlServer;
private MySql _mySql;
public Order(MSSQLServer mssqlServer)
{
_mssqlServer = mssqlServer;
}
public Order(MySql mySql)
{
_mySql = mySql;
}
public void Add()
{
_mssqlServer.Insert();
}
public void AddByMySql()
{
_mySql .Insert();
}
}
setp 3 整體貫通,實現需求
static void Main()
{
var mySql= new MySql();
var orderService = new OrderService(mySql);
orderService.InsertByMySql();
}
一個潛力的員工是這樣擴展的
代碼編號03 需求變更:改用MySql存儲訂單信息
setp 1 構建數據庫訪問接口
public interface IDataAccess
{
void Insert();
}
setp 2 實現MySql環境
public class MySqlDataAccess : IDataAccess
{
public void Insert(){...}
}
setp 3 改造MSSQLServer環境
public class MSSQLServerDataAccess : IDataAccess
{
public void Insert(){...}
}
setp 4 改造訂單服務,向IDataAccess環境添加數據
public class OrderService
{
private IDataAccess _dataAccess;
public Order(IDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public void Add()
{
_dataAccess .Insert();
}
}
setp 5 整體貫通,實現需求
static void Main()
{
var mySql= new MySqlDataAccess();
var orderService = new OrderService(mySql);
orderService.Insert();
}
Leader是這樣評價的
首先,02和03兩段代碼都能實現新的需求。
其次,03的代碼比02的代碼,更加的乾淨整潔。尤其是在OrderService中。
第三,02的每一次擴展,涉及到每個部分,包括新的實現方式、OrderService和貫通的部分。但03的每一次擴展,OrderService部分不需要改變。新增或是修改,改變了現有的其他模塊,就有可能出現Bug,如果能儘可能的不改變一些模塊,系統會變的更柔韌。
第四,如果需求要求使用DB2或Oracle來存儲訂單信息。03代碼的實現,毫無疑問的更加容易實現,系統做到了好的擴展性。
第五,如果需求要求使用DB2或Oracle來存儲訂單信息。03代碼的實現,毫無疑問更加簡單,也意味着系統更加高效。
依賴倒置設計原則DIP的誕生
總結:03的實現方式帶來了種種好處。因爲OrderService使用的是存儲的接口,不需要關心是使用哪種存儲的實現方式。OrderService通過IDataAccess接口來耦合具體的實現,不需要耦合MSSQLServer還是MySql,由一種強耦合變成了弱耦合,耦合度降低。
如果把最終使用接口的模塊OrderService定義爲高層模塊,把提供服務實現手段的定義爲底層模塊,總結出:
高層模塊需要其他低層模塊什麼功能,把需求抽象爲一個低層模塊的接口
各種低層模塊的實現按着這個接口去實現
前輩大牛將這句話精煉爲
高層模塊不應該依賴低層模塊,兩者應該依賴於抽象 |
抽象不應該依賴於實現,實現應該依賴於抽象 |
這就是依賴倒置設計原則DIP的誕生
生活中的應用
插頭標準規定三插頭的每個插頭的寬度、高度、每兩個插頭間的距離等標準。插座的設計只要能滿足三插頭的標準,其他電器的三插頭按照標準去實現,這樣不管是電視、冰箱還是筆記本的插頭,都可以使用這個插座。
反之插頭也不需要關心用的插座是公牛還是紅牛的。
ATM機的銀行卡插槽只要設計滿足於銀聯卡,就不需要關心取款人用的是工行卡還是農行卡。
USB的接口標準統一後,筆記本上的USB插口可以使用鼠標、鍵盤、U盤、硬盤。