關鍵句:乙個類只負責乙個職責
看例子理解:
class animal
} public
class client
}
執行結果不必多說,但是後面我們發現這個animal類還會包括魚,animal.breathe(「魚」),顯然常見的魚並不是通過肺來呼吸的,這時我們就需要修改了。這裡也就發生了職責擴散,職責擴撒就是由於某種原因,職責需要細分為職責1和職責2
我們可能會這樣改:
(1)修改animal類的breathe方法:(不建議的修改方式)
public
void
breathe(string animal)else
}
上面這種修改方式是很簡單,但是存在進一步的風險,假如往後的某一天,我們知道了某些魚還會用其他方式呼吸,這樣我們又要進一步修改這個類,這時我們的修改可能就會影響到 牛 羊 等呼吸方式。這也違背了單一職責原則,所以這種方式不可取。
(2)增加animal類新的breathe方法:(根據實際情況確定是否使用)
class animal
public
void
breathe2(string animal)
}
上面修改方式,在方法級別符合單一職責原則,因為它並沒有動原來方法的**。類級別是違背單一職責原則。這種方式在類中方法足夠少的情況下可以考慮使用。
(3)細分animal類:(標準的,不違反單一職責的方式)
class terrestrial
} class aquatic
}
上面修改的方式,修改花銷是很大的,除了將原來的animal類分解之外,還需要修改客戶端。即:
terrestrial terrestrial = new terrestrial();
terrestrial.breathe("牛");
aquatic aquatic = new aquatic();
aquatic.breathe("魚");
所以,上面(2)(3)修改方式需要綜合專案的複雜程度等選擇使用(如何選擇使用上面已經有說到)
關鍵句:子類可以擴充套件父類的功能,但不能改變父類原有的功能
這個原則主要是針對繼承而言的,因為繼承往往有這樣的含義:父類中已經實現的方法,其實也就是針對該類部分行為的描述和定義。而若子類對這個方法進行任意修改,那麼就會造成繼承體系的破壞。
實際程式設計中,我們常常會通過重寫父類的方法來完成新的功能,這樣寫起來雖然簡單,但是整個繼承體系的**的可復用性會比較差。
如果非要重寫父類的方法,比較通用的做法是:原來的父類和子類都繼承乙個更通俗的基類,原有的繼承關係去掉,採用依賴、聚合,組合等關係代替。
關鍵句:細節應該依賴抽象,面向介面程式設計
看例子理解這個原則:
class book
} class mother
} public
class client
}
上面的例子有乙個mother類,有乙個book類,book類作為乙個引數傳入到mother類中,這樣,mother類就完成了對book類的讀取。
但是這時候,要增加乙個需求,mother要讀報紙,與book類相似,news*****類如下:
class news*****
}
這時候我們就發現,mother類的narrate方法只接受book的物件,並不會讀news*****,所以我們考慮如下修改方式:
(1)mother類增加narrate1方法,傳入news*****。
絕對的坑爹設計,以後如果還有 雜誌、**要讀,那是不是會有更多方法需要增加,mother類需要不斷修改。
(2)面向介面程式設計,引入介面ireader。
inte***ce ireader
mother類與介面ireader發生依賴關係,而book和news*****都屬於讀物的範疇,他們各自都去實現ireader介面,這樣就符合依賴倒置原則了,**修改為:
class
news*****
implements
ireader
} class
book
implements
ireader
} class
mother
} public
class
client
}
遵循依賴倒置原則可以降低類之間的耦合性,提高系統的穩定性,降低修改程式造成的風險。
關鍵句:客戶端不應該依賴它不需要的介面;乙個類對另乙個類的依賴應該建立在最小的介面上
這個原則解決這樣乙個問題:
類a通過介面 i 依賴類b,類c通過同樣的介面 i 依賴類d。這是介面 i 有類b和類d的方法,但是對於類b和類d他們彼此並不需要對方的方法。這時,介面 i 的就過於臃腫,因此需要拆分。
這個原則比較好理解,這裡不再用例子解釋。需要記住的就是建立單一介面,不要建立龐大臃腫的介面,適度細化介面,介面中的方法盡量少。
關鍵句:乙個物件應該對其他物件保持最少的了解,盡量降低類與類之間的耦合
這個原則也可以這樣理解,類僅與直接的朋友通訊。(直接的朋友包括:成員變數、方法引數、方法返回值)
舉個例子,現在有如下程式:
//總公司員工
class employee
public string getid()
}//分公司員工
class subemployee
public string getid()
}
現在需要輸出整個公司員工的id,我們可能會這樣寫**:
class
subcompanymanager
return
list;
}}class
companymanager
return
list;
}public void printallemployee(subcompanymanager sub)
list
list2 = this.getallemployee();
for(employee e:list2)
}}
在分公司subcompanymanager類中建立方法getallemployee()
在總公司companymanager類中建立方法getallemployee()和printallemployee()。
根據迪公尺特法則,comanymanager與employee是直接朋友,但是與subemployee並不是直接朋友。這樣總公司與分公司邏輯上是耦合的了。所以這種方式不可取,需要修改:
class
subcompanymanager
return
list;
}public void printemployee()
}}class
companymanager
return
list;
}public void printallemployee(subcompanymanager sub)
}}
上面方法就有效的降低了類之間耦合,僅與直接的朋友進行了通訊。
關鍵句:類、模組、功能應該對擴充套件開放,對修改關閉
開閉原則中「開」,是指對於元件功能的擴充套件是開放的,是允許對其進行功能擴充套件的;
開閉原則中「閉」,是指對於原有**的修改是封閉的,即不應該修改原有的**。
之前提到的黎克特制代換原則、依賴倒置原則、介面隔離原則,還有我們知道的抽象類、介面等等,都可以看作是開閉原則的實現方法。
設計模式基本原則
設計模式基本原則 開 閉 原則 open closed principle,或者ocp 原文 software entities should be open for extension,but closed for modification.解釋 乙個軟體實體應當對擴充套件開放,對修改關閉。黎克特...
設計模式基本原則
1 單一職責原則 類的職責要單一 不要將太多的職責放到同乙個類當中去。eg 資料結構職責類和演算法行為都放在乙個類。我們應該把資料結構和行為分開。2 開閉原則 乙個軟體實體應該對擴充套件開放,對修改關閉。可變性封裝 3 黎克特制代換原則 可以接受基類物件的地方必然要可以接受子類的物件。4 依賴倒轉原...
設計模式基本原則
設計模式基本原則 開 閉 原則 open closed principle,或者ocp 原文 software entities should be open for extension,but closed for modification.解釋 乙個軟體實體應當對擴充套件開放,對修改關閉。黎克特...