首先感謝宗傳奇大神 送了我一本《設(shè)計(jì)模式之禪》呀忧,春節(jié)期間把這本書(shū)快速的讀了一遍。
很久前對(duì)設(shè)計(jì)原則有過(guò)學(xué)習(xí),但并沒(méi)有去在意滥壕。最近幾天寫(xiě)代碼,發(fā)現(xiàn)寫(xiě)代碼的時(shí)候腦子里會(huì)冒出這用的是‘開(kāi)閉原則’兽泣,或 準(zhǔn)備寫(xiě)代碼的 問(wèn)一下自己會(huì)用到什么原則绎橘。雖然設(shè)計(jì)原則不能幫助你現(xiàn)實(shí)任何業(yè)務(wù),也不能明顯的減少代碼的開(kāi)發(fā)量唠倦,但是很神奇称鳞。說(shuō)它是禪,一點(diǎn)都不過(guò)分稠鼻。
由于領(lǐng)悟尚淺冈止,方便回味,自己寫(xiě)了簡(jiǎn)潔的案例候齿;同時(shí)也希望各位大神熙暴,建議指導(dǎo);
-
開(kāi)閉原則(Open-Closed Principle, OCP)
一個(gè)軟件實(shí)體應(yīng)當(dāng)對(duì)擴(kuò)展開(kāi)放慌盯,對(duì)修改關(guān)閉周霉。即軟件實(shí)體應(yīng)盡量在不修改原有代碼的情況下進(jìn)行擴(kuò)展。
重構(gòu)前亚皂,只要節(jié)目有變就要改春晚代碼
//春晚演節(jié)目 (重構(gòu)前)
public void chunWan(String name){
if("賈玲".equals(name)){
JiaLing jiaLing=new JiaLing();
jiaLing.xiaoPin();
}else if("王菲".equals(name)){
Wangfei wangfei=new Wangfei();
wangfei.changGe();
}
}
重構(gòu)后俱箱,讓春晚演節(jié)目更靈活。
//春晚演節(jié)目 (重構(gòu)后)
public void chunWan(YanYuan yanYuan){
yanYuan.biaoYan();
}
//抽象出一個(gè)演員抽象類(lèi),添加一個(gè)biaoYan抽象方法.
public abstract class YanYuan {
public abstract void biaoYan();
}
//讓賈玲繼承 演員抽象類(lèi) 并實(shí)現(xiàn)biaoYan抽象方法.
public class JiaLing extends YanYuan{
@Override
public void biaoYan() {
System.out.println("賈玲開(kāi)始小品表演");
}
}
//王菲亦如此,實(shí)現(xiàn)表演唱歌. 從此所有人繼承演員就可以上春晚了!
...
-
里氏替換原則(Open-Closed Principle, OCP)
子類(lèi)可以擴(kuò)展父類(lèi)的功能灭必,但不能改變父類(lèi)原有的功能狞谱。所有引用父類(lèi)的地方必須能透明地使用其子類(lèi)的對(duì)象。
重構(gòu)前禁漓,功能混亂沒(méi)有約束跟衅,容易出錯(cuò),弄不好就掛了璃饱。
public static void main(String[] args) {
Guo guo = new PingDiGuo();
//找個(gè) 鍋 來(lái) 烹飪
zuoFan(guo);
//結(jié)果 拿鍋拍人去了
}
//傳入鍋來(lái)做飯
public static void zuoFan(Guo guo){
guo.function();
}
//可以做飯的鍋類(lèi)
public static class Guo{
public void function(){
System.out.println("我來(lái)烹飪了");
}
}
//一只平底鍋
public static class PingDiGuo extends Guo{
public void function(){
System.out.println("發(fā)現(xiàn)平底鍋,可以殺人越貨,我要維護(hù)世界和平");
}
}
重構(gòu)后与斤,保留鍋的本質(zhì)功能,平底鍋特有功能應(yīng)該獨(dú)自實(shí)現(xiàn)。
public static void main(String[] args) {
Guo guo = new PingDiGuo();
//找個(gè) 鍋 來(lái) 烹飪
zuoFan(guo);
//鍋的本質(zhì)功能 被保留
}
//傳入鍋來(lái)做飯
public static void zuoFan(Guo guo){
guo.function();
}
//可以做飯的鍋類(lèi)
public static class Guo{
public final void function(){
System.out.println("我來(lái)烹飪了");
}
}
//一只平底鍋
public static class PingDiGuo extends Guo{
public void newFunction(){
System.out.println("發(fā)現(xiàn)平底鍋,可以殺人越貨,我要維護(hù)世界和平");
}
}
小結(jié): 子類(lèi)可以擴(kuò)展父類(lèi)的功能撩穿,但不能改變父類(lèi)原有的功能磷支。
里氏替換原則 舉例非常困難,簡(jiǎn)單的總結(jié)一下
1:不能重寫(xiě)父類(lèi)本質(zhì)的非抽象方法食寡。
2:父類(lèi)本質(zhì)功能,不想被重寫(xiě)可以加 final雾狈。
3:在子類(lèi)中增加自己特有的方法。
4:當(dāng)子類(lèi)的方法重載父類(lèi)的方法時(shí)抵皱,方法的前置條件(即方法的形參)要比父類(lèi)方法的輸入?yún)?shù)更寬松善榛。
5:當(dāng)子類(lèi)的方法實(shí)現(xiàn)父類(lèi)的抽象方法時(shí),方法的后置條件(即方法的返回值)要比父類(lèi)更嚴(yán)格呻畸。
-
依賴(lài)倒置原則(Dependency Inversion Principle, DIP)
高層模塊不應(yīng)該依賴(lài)低層模塊移盆,兩者都應(yīng)該依賴(lài)其抽象。抽象不應(yīng)該依賴(lài)于細(xì)節(jié)伤为。
細(xì)節(jié)應(yīng)當(dāng)依賴(lài)于抽象咒循。換言之,要針對(duì)接口編程绞愚,而不是針對(duì)實(shí)現(xiàn)編程叙甸。
重構(gòu)前,擴(kuò)展差位衩,不符合開(kāi)閉原則裆蒸。并且功能容易混亂。
//有個(gè)唱歌節(jié)目 傳進(jìn)不同的人唱歌
public void play(People ren){
ren.changGe();
}
//過(guò)了一段時(shí)間突然有只 鳥(niǎo) 也來(lái)節(jié)目 唱歌 ,然后節(jié)目 擴(kuò)展 了一個(gè) 方法
public void play(Bird niao){
niao.changGe();
}
//漸漸時(shí)間舊了,發(fā)現(xiàn)兩個(gè)問(wèn)題 ,
// 1:不是所有的人或鳥(niǎo)都會(huì)唱歌;
// 2:還有其他動(dòng)物也會(huì)唱歌;
重構(gòu)后糖驴,想去參加唱歌節(jié)目僚祷,就必須實(shí)現(xiàn)唱歌,簡(jiǎn)單清楚遂赠。
//抽象出一個(gè) 歌曲類(lèi) , 有開(kāi)始唱的功能;
public abstract class Song{
public abstract void play();
}
// 節(jié)目組做了調(diào)整 , 需求更明確 , 要求會(huì)唱歌的來(lái), 不會(huì)唱歌的就不能來(lái)
public void play(Song geQu){
geQu.play();
}
//所以 接下來(lái) 想去 參加節(jié)目的 就必須要會(huì)唱歌 (實(shí)現(xiàn)Song)
-
接口隔離原則(Interface Segregation Principle, ISP)
客戶端不應(yīng)該依賴(lài)它不需要的接口久妆。類(lèi)間的依賴(lài)關(guān)系應(yīng)該建立在最小的接口上。
重構(gòu)前跷睦,
//有個(gè)演員抽象類(lèi) 會(huì)唱歌 繼承了唱歌 功能
public interface YanYuan extends Song{
void playSong();
}
//節(jié)目 邀請(qǐng) 演員 來(lái)唱歌
public void JieMu(YanYuan yanYuan){
yanYuan.playSong();
}
重構(gòu)后,
//演員抽象類(lèi) 會(huì)唱歌
public interface YanYuan {
void playSong(Song song);
}
//節(jié)目開(kāi)始 歌 被演員唱了起來(lái)
public void JieMu(YanYuan yanYuan){
yanYuan.playSong(getSong());
}
//接口隔離原則能從很多 維度舉例; 拆分細(xì)化等;
//個(gè)人看標(biāo)題的表面意思 理解 更偏向于,接口回調(diào),接口解耦方面....
-
迪米特法則(Law of Demeter, LoD)
一個(gè)軟件實(shí)體應(yīng)當(dāng)盡可能少地與其他實(shí)體發(fā)生相互作用肋演。
重構(gòu)前抑诸,
//一個(gè)教室類(lèi) 里面有很多電器
public class JiaoShi{
//各種電器
public KongTiao kongTiao;//空調(diào)
public Deng deng;//燈
public YinShuiJi yinShuiJi;//飲水機(jī)
....
}
//一個(gè)老師類(lèi) 有檢查關(guān)閉電源 的方法
public class Teacher{
public void jianChaDianYuan(JiaoShi jiaoShi){
jiaoShi.kongTiao.close();//關(guān)空調(diào)
jiaoShi.deng.close();//關(guān)燈
jiaoShi.yinShuiJi.close();//關(guān)飲水機(jī)
}
}
//老師需要 知道所有電器 并關(guān)閉
重構(gòu)后,
//一個(gè)教室類(lèi) 里面有很多電器
public class JiaoShi{
//各種電器
public KongTiao kongTiao;//空調(diào)
public Deng deng;//燈
public YinShuiJi yinShuiJi;//飲水機(jī)
....
//一個(gè) 開(kāi)關(guān)
public void closeAll(){
jiaoShi.kongTiao.close();//關(guān)空調(diào)
jiaoShi.deng.close();//關(guān)燈
jiaoShi.yinShuiJi.close();//關(guān)飲水機(jī)
}
}
//一個(gè)老師類(lèi) 只需要知道一個(gè)開(kāi)關(guān)即可
public class Teacher{
public void jianChaDianYuan(JiaoShi jiaoShi){
jiaoShi.closeAll();
}
}
//還有一個(gè)層面的理解: 抽出一個(gè) 總閘開(kāi)關(guān) 接口, 有個(gè)抽象方法 closeAll();
//只需要傳給老師 總閘開(kāi)關(guān) , 老師調(diào)用 總閘開(kāi)關(guān)的closeAll(),就能關(guān)閉所有電源
//然而不需要關(guān)心具體關(guān)閉什么電器, 這樣電器 和 老師 就解耦了
-
單一職責(zé)原則(Single Responsibility Principle, SRP)
一個(gè)類(lèi)只負(fù)責(zé)一個(gè)功能領(lǐng)域中的相應(yīng)職責(zé)爹殊,或者可以定義為:就一個(gè)類(lèi)而言蜕乡,應(yīng)該只有一個(gè)引起它變化的原因。
重構(gòu)前梗夸,
//茶農(nóng)類(lèi), 從前有個(gè)很辛苦的 茶農(nóng) ,
public class ChaNong{
//他要負(fù)責(zé)種茶葉
public void zhongCha(){
System.out.println("種茶,收茶");
}
//還需要加工茶葉
public void jiaGongCha(ChaYe chaYe){
System.out.println("加工了100盒");
}
//然后去集市賣(mài)茶
public void maiCha(ChaYe chaYe){
System.out.println("成功賣(mài)了100盒,收到了很多錢(qián)");
}
}
重構(gòu)后层玲,
//加工廠類(lèi), 由于茶農(nóng)辛苦 ,收益底 ,一個(gè)很有眼光的人, 開(kāi)了一家 加工茶葉銷(xiāo)售公司
public class JiaGongChang{
//加工茶葉
private void jiaGongCha(ChaYe chaYe){
System.out.println("加工了100盒");
}
//然后批發(fā)茶葉到市場(chǎng)
public Money maiCha(ChaYe chaYe){
jiaGongCha(chaYe);
System.out.println("成功賣(mài)了100盒,收到了很多錢(qián)");
...
return money;
}
}
//茶農(nóng)類(lèi), 從此 茶農(nóng) 就有了 清閑 的生活
public class ChaNong{
//他只負(fù)責(zé)種茶
public void zhongCha(){
System.out.println("勞動(dòng)最光榮");
}
//然后去集市賣(mài)茶
public void maiCha(ChaYe chaYe){
Money money =new JiaGongChang().maiCha(chaYe);
System.out.println(money);
}
}
本文是作者通過(guò)再次學(xué)習(xí)后的理解總結(jié),希望能為大家?guī)?lái)幫助; 謝謝,謝謝宗傳奇贈(zèng)書(shū)
推薦鏈接: 設(shè)計(jì)模式之六大原則(轉(zhuǎn)載)
推薦鏈接: 迪米特法則