設(shè)計(jì)模式的目的
編寫(xiě)程序過(guò)程中,開(kāi)發(fā)人員面臨著來(lái)自耦合性、內(nèi)聚性以及可維護(hù)性、可擴(kuò)展性、重用性、靈活性等多方面的挑戰(zhàn),設(shè)計(jì)模式是為了讓程序具有更好的代碼重用性(相同功能,不用多次編寫(xiě))、可讀性(編碼規(guī)范性)、可擴(kuò)展性(可維護(hù)性)、可靠性(增加新功能,對(duì)原來(lái)功能沒(méi)有影響)、高內(nèi)聚低耦合的特性。
設(shè)計(jì)模式包含了面向?qū)ο蟮木?,“懂了設(shè)計(jì)模式,你就懂了面向?qū)ο蠓治龊驮O(shè)計(jì)(OOA/D)的精要”
Scott Mayers在其巨著《Effective C++》中就曾說(shuō)過(guò):C++老手和C++新手的區(qū)別就是前者手背上有很多傷疤。
設(shè)計(jì)模式七大原則
開(kāi)發(fā)人員在編程時(shí)應(yīng)當(dāng)遵守的原則,也是各種設(shè)計(jì)模式的基礎(chǔ)(設(shè)計(jì)模式為什么這樣設(shè)計(jì)的依據(jù))
單一職責(zé)原則(Single Responsibility Principle)
一個(gè)類應(yīng)該只負(fù)責(zé)一項(xiàng)職責(zé)。如類A負(fù)責(zé)職責(zé)1、職責(zé)2兩項(xiàng)職責(zé),當(dāng)職責(zé)1需求變更改變A時(shí),可能造成職責(zé)2執(zhí)行錯(cuò)誤。應(yīng)將A分解為A1、A2。
方案1:

改進(jìn)方案:
在方式1的方法中違反了單一職責(zé)原則
根據(jù)交通工具運(yùn)行方式的不同,分解成不同類
方案2:

改進(jìn)方案:
遵守單一職責(zé)原則,但改動(dòng)很大,同時(shí)需修改客戶端
直接修改類,改動(dòng)代碼少
方案3:

沒(méi)有對(duì)類做大的修改,只是增加方法(盡量慎用if()elseif()elseif()...分支)
雖然沒(méi)有在類級(jí)別上遵守單一職責(zé)原則,但在方法級(jí)別,仍然遵守單一職責(zé)
單一職責(zé)原則注意事項(xiàng)和細(xì)節(jié)
降低累的復(fù)雜度,一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé)
提高類的可讀性、可維護(hù)性
降低變更引起的風(fēng)險(xiǎn)
通常情況下,我們應(yīng)該遵守單一職責(zé)原則,只有邏輯足夠簡(jiǎn)單,才可以在代碼級(jí)違反單一職責(zé)原則,只有類中方法數(shù)量足夠少,可以在方法級(jí)保持單一職責(zé)原則(單一職責(zé)是相對(duì)的,關(guān)鍵是確定單一職責(zé)的顆粒度,顆粒度達(dá)到一定級(jí)別,必須拆分方法甚至類)
接口隔離原則(Interface Segregation Principle)
客戶端不應(yīng)依賴它不需要的接口,即一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上
方案1:

改進(jìn)方案:
Interface1對(duì)于AC不是最小接口,那BD就會(huì)實(shí)現(xiàn)他們不需要的方法
按隔離原則處理,將Interface拆分為獨(dú)立的幾個(gè)接口分別與AC建立依賴關(guān)系。
方案2:

依賴倒轉(zhuǎn)(倒置)原則(Dependence Inversion Principle)
高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)依賴其抽象
抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴抽象
依賴倒轉(zhuǎn)(倒置)的中心思想是面向接口編程
依賴倒轉(zhuǎn)原則是基于這樣的設(shè)計(jì)理念:相對(duì)于細(xì)節(jié)的多變性,抽象的東西要穩(wěn)定的多。以抽象為基礎(chǔ)搭建的框架比以細(xì)節(jié)為基礎(chǔ)搭建的框架要穩(wěn)定的多。在java中抽象指的是接口或抽象類,細(xì)節(jié)就是具體的實(shí)現(xiàn)類
使用接口和抽象類的目的是制定好規(guī)范,而不涉及任何具體的操作,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成
抽象類和接口的區(qū)別: http://www.itdecent.cn/p/038f0b356e9a
方案1:

改進(jìn)方案:
如果我們獲取的對(duì)象是微信、短信等等,則新增類的同時(shí)也要在Person類中增加相應(yīng)接收方法
引入一個(gè)抽象接口Receiver表示接收者,Person類與接口Receiver發(fā)生依賴,郵件、微信、短信去實(shí)現(xiàn)Receiver接口即可,這樣符合依賴倒轉(zhuǎn)原則

依賴關(guān)系傳遞:
接口傳遞
構(gòu)造方法傳遞
setter傳遞
https://www.kancloud.cn/sstd521/design/193500
依賴倒轉(zhuǎn)原則的注意事項(xiàng)和細(xì)節(jié)
低層模塊盡量都要有抽象類和接口,或者兩者都有,程序穩(wěn)定性更好
變量的聲明類型盡量是抽象類或接口,這樣變量引用和實(shí)際對(duì)象間,就存在一個(gè)緩沖層,利于程序擴(kuò)展和優(yōu)化
繼承時(shí)遵循里式替換原則
里式替換原則(Liskov Substitution Principle)
里式替換原則(Liskov Substitution Principle)1988年,由麻省理工一位姓里的女士提出的
如果對(duì)每個(gè)類型為T(mén)1的對(duì)象o1,都有類型為T(mén)2的對(duì)象o2,使得以T1定義的所有程序P在所有的對(duì)象o1都代換為o2時(shí),程序P的行為沒(méi)有發(fā)生變化,那么類型T2是類型T1的子類型。換句話說(shuō),所有引用基類的地方必須能夠透明地使用其子類的對(duì)象
在使用繼承時(shí),遵循里式替換原則,在子類中盡量不要重寫(xiě)父類的方法(不需要重寫(xiě)的方法提至基類,大家去繼承,需要重寫(xiě)的方法單獨(dú)實(shí)現(xiàn))
繼承實(shí)際上讓兩個(gè)類耦合性增強(qiáng),在適當(dāng)?shù)那闆r下,可通過(guò)依賴、聚合、組合來(lái)解決問(wèn)題
OO中的繼承性的思考和說(shuō)明
繼承包含這樣一層含義:父類中凡是已經(jīng)實(shí)現(xiàn)好的方法,實(shí)際上是在設(shè)定規(guī)范和契約,雖然它不強(qiáng)制要求所有的子類必須遵循這些契約(重寫(xiě)),但是如果子類對(duì)這些已經(jīng)實(shí)現(xiàn)的方法任意修改,就會(huì)對(duì)整個(gè)繼承體系造成破壞
繼承在給程序設(shè)計(jì)帶來(lái)便利的同時(shí),也帶來(lái)了弊端。比如使用繼承會(huì)給程序帶來(lái)侵入性,程序的可移植性降低,增加了對(duì)象間的耦合性,如果一個(gè)類被其他的類所繼承,則當(dāng)這個(gè)類需要修改時(shí),必須考慮到所有的子類,并且父類修改后,所有涉及到子類的功能都可能產(chǎn)生故障。
編程中如何正確的使用繼承→里式替換原則

改進(jìn)方案:
原來(lái)的父類、子類都繼承更通俗的基類,原有的繼承關(guān)系去掉,采用依賴、聚合、組合等關(guān)系替代。
開(kāi)閉原則(Open Close Principle)
開(kāi)閉原則(Open Close Principle)是編程中最基礎(chǔ)、最重要的設(shè)計(jì)原則
一個(gè)軟件實(shí)體,如類,模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開(kāi)放(提供方),對(duì)修改關(guān)閉(使用方)。用抽象構(gòu)建框架,用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié)
當(dāng)軟件需要變化時(shí),盡量通過(guò)擴(kuò)展軟件實(shí)體的行為來(lái)實(shí)現(xiàn)變化,而不是通過(guò)修改已有的代碼來(lái)實(shí)現(xiàn)變化
編程中遵循其他原則,以及使用設(shè)計(jì)模式的目的就是遵循開(kāi)閉原則
方案1:

改進(jìn)方案:
違反了設(shè)計(jì)模式的OCP原則,即對(duì)外擴(kuò)展開(kāi)放(提供方),對(duì)修改關(guān)閉(使用方)。即當(dāng)我們給類增加新功能的時(shí)候,盡量不修改代碼或盡可能少修改代碼
將Shape類做成抽象類,提供一個(gè)抽象的draw方法,讓子類去實(shí)心即可,這樣我們新增圖形種類時(shí),只需讓新圖形類繼承Shape,并實(shí)現(xiàn)draw方法即可,使用方代碼不需要修改
方案2:

迪米特原則(Demeter Principle)
一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解
類與類關(guān)系越密切,耦合度越大
迪米特原則(最少知道原則)即一個(gè)類對(duì)自己依賴的類知道的越少越好,也就是說(shuō),對(duì)于被依賴的類不管多復(fù)雜,都盡量將邏輯封裝在類的內(nèi)部。對(duì)外除了提供public方法,不對(duì)外泄露任何信息
迪米特法則還有個(gè)更簡(jiǎn)單的定義:只與直接的朋友通信
直接的朋友:每個(gè)對(duì)象都會(huì)與其他對(duì)象有耦合關(guān)系,只要兩個(gè)對(duì)象間有耦合關(guān)系,我們就說(shuō)這兩個(gè)對(duì)象之間是朋友關(guān)系,耦合的方式有很多,依賴、關(guān)聯(lián)、組合、聚合等。其中我們稱出現(xiàn)在成員變量、方法參數(shù)、方法返回值中的類為直接朋友,而出現(xiàn)在局部變量中的類不是直接朋友(也就是說(shuō),陌生的類最好不要以局部變量的形式出現(xiàn)在類中)。
迪米特原則的注意事項(xiàng)和細(xì)節(jié)
迪米特原則的核心是降低類之間的耦合性
但是注意,每個(gè)類都減少了不必要的依賴,因此迪米特原則只是要求降低類間(對(duì)象間)耦合關(guān)系,并不是要求完全沒(méi)有依賴關(guān)系
合成復(fù)用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承(會(huì)使類與類之間耦合性增強(qiáng))。

設(shè)計(jì)原則核心思想
找出應(yīng)用中可能需要變化之處,把他們獨(dú)立出來(lái),不要和那些不需要變化的代碼混在一起
針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程
為了交互對(duì)象間的松耦合設(shè)計(jì)而努力