第五章依賴倒換原則5.1何謂依賴倒換原則
依賴倒換原則(Dependence Inversion Principle)簡稱DIP(別名依賴倒轉原則或依賴倒置原則),它有兩種定義。
定義一:“a.高層模組不應該依賴於低層模組。二者都應該依賴於抽象。b.抽象不應該依賴於細節,細節應當依賴於抽象。” [1]
簡言之,我們在設計系統時,需要運用抽象來分析,而不必一開始關注類的劃分或細節。
定義二:“要針對介面編程,不要針對實現編程。 ”[2]
簡言之,我們運用依賴倒換原則時,可以通過介面與抽象類別去進行各種變數、參數、方法等的聲明。並且,禁止實作類別去做以上各種聲明。
綜上所述,我們可以把依賴倒換原則理解成現實生活中的一些事情。比如,孕婦與龍鳳胎。
有孕婦,才能產生龍鳳胎。孕婦是抽象,龍鳳胎(包括男嬰、女嬰)是實現。具體類圖如所示:
http://hi.csdn.net/attachment/201111/1/0_13201170861avv.gif
圖5.1
5.2為何要實現依賴倒換
為何要遵循依賴倒換原則,我們可以從以下兩點進行分析:
一. 倒換的緣由:
當前,在我們軟體項目開發過程中,為了使代碼重用。我們經常會把一些通用的函數和功能寫成通用模組,以方便有需要的開發人員調用。
如果我們的通用模組設計的不合理,則無法發揮其功能。比如,我們在類型轉換功能類中封裝ORACLE格式的代碼,而我們新項目使用的是SQL SERVER。此時,調用該通用模組必然會出錯。為瞭解決這一問題,我們必定要重構代碼,此時依賴倒換則派上用場。我們通過在介面中定義ORACLE、SQL SERVER等資料庫的轉換方法,在SQL SERVER 具體實作類別中實現介面方法即可。如此一來,無論將來新項目使用ORACLE,還是其他資料庫,通用模組都無需修改或增加代碼。
二. 依賴介面的作用:
作為完整抽象描述的介面,其作用,我們可以通過一個通俗的執行個體進行理解。
比如,當前居民使用者家中,以插口方式進行網路式串連的電信IPTV電視盒。如果IPTV的機房網路連接進行了變換,此時他們只需在機房中進行變換,而我們的IPTV電視盒仍沿用原插口。如果不是通過插口來使用電視盒,而是通過直接與電視站進行線路串連;則在網路方式發生變化時,線路很有可能要進行改造,並且增加了安全風險。
由此可見,介面大大的提高了系統的擴充性和靈活性。
5.3如何?依賴倒換
如何使用依賴倒換原則,是一個值得讓人深思的課題。
我們不妨從以下幾個方面去考慮:
1. 從實作類別與抽象類別的角度進行分析。我們在運用具體實作類別去繼承抽象類別時,需要保證引用‘基類’之處可修改成其子類。
2. 從層次關係角度進行分析。我們需要定義清晰的層次關係,使每個層次通過介面的方式進行。
3. 從物件建構角度進行分析。如果建立的是動態對象,則使用依賴倒換。如果建立的是一些靜態具體類並且變動率很低,則我們無需再建立其基類去繼承,以規避維護多餘代碼的風險。
綜上所述,我們在使用依賴倒換原則時,需要在完全理解定義的基礎上;運用分層的概念,通過具體實作類別去調用介面或抽象類別,最終達到高效、清晰、系統擴充靈活的效果。
5.4應用反思
某外貿小公司剛成立不久,為了開展B2C業務需要進行網站開發,公司老闆委託我幫忙招收兩個一、二年開發經驗的普通JAVA程式員。此時,我設計了一些題目。其中,以一個員工管理小模組作為設計考題。具體內容如下:
本公司人員包括管理層與業務員,現因業務需要招收兩名JAVA程式員。(請根據依賴倒換原則對公司人員管理進行設計,只需建立JAVA類圖與簡要代碼。)
筆試的程式員中主要有二種回答:
一. 違反依賴倒換原則的回答
設計三個類,管理層、業務員、程式員各建立一個類。
http://hi.csdn.net/attachment/201111/1/0_1320117116qr2G.gif
圖5.2
即原始碼為:
程式5.4.1
(一) 管理層
import java.util.List;
import java.util.Map;
public class Employee {
public void Employee() {
}//員工介面
public int selectCount(String sql,Object entity) {
return 0;
}
//插入資料
public Object insert(String sql,Object entity) {
return null;
}
//修改資料
public Object update(String sql,Object entity) {
return null;
}
//刪除資料
public Object delete(String sql,Object entity) {
return null;
}
//聯集查詢方法
public List selectUnite(String sql,Map map) {
return null;
}
}
(二) 業務員
import java.util.List;
import java.util.Map;
public class Salesman {
public void Salesman() {//業務員類
}
public Object delete(String sql, Object entity) {
return null;
}
public Object insert(String sql, Object entity) {
return null;
}
public int selectCount(String sql, Object entity) {
return 0;
}
public List selectUnite(String sql, Map map) {
return null;
}
public Object update(String sql, Object entity) {
return null;
}
}
(三) 程式員
import java.util.List;
import java.util.Map;
public class Programmer {//程式員
public void Programmer() {
}
public Object delete(String sql, Object entity) {
return null;
}
public Object insert(String sql, Object entity) {
return null;
}
public int selectCount(String sql, Object entity) {
return 0;
}
public List selectUnite(String sql, Map map) {
return null;
}
public Object update(String sql, Object entity) {
return null;
}
}
二. 符合依賴倒換原則的回答:
http://hi.csdn.net/attachment/201111/1/0_1320117131JJBo.gif
圖5.3
定義員工介面、業務員類、程式員類。
即原始碼為:
程式5.4.2
(一) 管理層
import java.util.List;
import java.util.Map;
public interface IEmployee {
public void IEmployee();//員工介面
public int selectCount(String sql,Object entity);
//插入資料
public Object insert(String sql,Object entity);
//修改資料
public Object update(String sql,Object entity);
//刪除資料
public Object delete(String sql,Object entity);
//聯集查詢方法
public List selectUnite(String sql,Map map);
}
(二) 業務員
import java.util.List;
import java.util.Map;
public class Salesman implements IEmployee{//業務員實作類別
public void IEmployee() {
}
public Object delete(String sql, Object entity) {
return null;
}
public Object insert(String sql, Object entity) {
return null;
}
public int selectCount(String sql, Object entity) {
return 0;
}
public List selectUnite(String sql, Map map) {
return null;
}
public Object update(String sql, Object entity) {
return null;
}
}
(三) 程式員
import java.util.List;
import java.util.Map;
public class Programmer implements Iemployee{//程式員實作類別
public void Iemployee() {
}
public Object delete(String sql, Object entity) {
return null;
}
public Object insert(String sql, Object entity) {
return null;
}
public int selectCount(String sql, Object entity) {
return 0;
}
public List selectUnite(String sql, Map map) {
return null;
}
public Object update(String sql, Object entity) {
return null;
}
}
三. 對比兩種回答
違反依賴倒換原則的回答,建立了管理層、業務員、程式員三個具體類,如果三者增加同一個方法則需要修改三個類;而符合依賴倒換原則的回答,只需在員工介面中增加方法即可。相比之下,符合依賴倒換原則的回答更符合軟體開發的需求。因而,筆者最終聘用了符合依賴倒換原則進行回答的程式員。
5.5參考資料
[1] Robert C.Martin<< 敏捷式軟體開發 (Agile Software Development):原則、模式與實踐>>第116頁
[2] 閻宏<<JAVA與模式>>第87頁
博主蔣海昌(曾在學術期刊發表過設計模式、需求分析、專案管理的一些文章)對本部落格文章享有著作權。網路轉載請註明出處http://blog.csdn.net/alike188/article/details/6924112。整理出版物請和作者聯絡。有任何建議或意見,歡迎在評論中告知!QQ:2337605394,JAVA設計模式群
12999329