什么是設(shè)計(jì)模式
“每一個(gè)模式描述了一個(gè)在我們周?chē)粩嘀貜?fù)發(fā)生的問(wèn)題碧囊,以及該問(wèn)題的解決方案的核心帚桩。這樣,你就能一次又一次地使用方案而不必做重復(fù)勞動(dòng)吧雹」窃樱” -Christopher Alexander
依據(jù)我個(gè)人理解,在現(xiàn)實(shí)世界中雄卷,我們會(huì)遇到千奇百怪有矛盾的問(wèn)題搓蚪,解決的辦法也是五花八門(mén),但是真正有效龙亲,直擊痛點(diǎn)的方法又會(huì)更少陕凹,加之,倘若每一個(gè)問(wèn)題我們都去自己想辦法解決鳄炉,那么效率是堪憂(yōu)的杜耙。那么是否存在前人總結(jié)好的解決方案,供我們參考呢拂盯?以便我們結(jié)合實(shí)際問(wèn)題套用即可佑女?設(shè)計(jì)模式便是。
為什么需要設(shè)計(jì)模式
這就要?dú)w宿到軟件設(shè)計(jì)負(fù)責(zé)的根本原因是變化谈竿。
而設(shè)計(jì)模式就是用來(lái)處理變化與穩(wěn)定之間的矛盾的团驱。
軟件設(shè)計(jì)的金科玉律便是復(fù)用!
面向?qū)ο笤O(shè)計(jì)原則
面向?qū)ο蟮?個(gè)基本要素:封裝空凸、繼承嚎花、多態(tài)
面向?qū)ο蟮?個(gè)基本設(shè)計(jì)原則:
單一職責(zé)原則(Single-Resposibility Principle)
其核心思想為:一個(gè)類(lèi),最好只做一件事呀洲,只有一個(gè)引起它的變化紊选。單一職責(zé)原則可以看做是低耦合、高內(nèi)聚在面向?qū)ο笤瓌t上的引申道逗,將職責(zé)定義為引起變化的原因兵罢,以提高內(nèi)聚性來(lái)減少引起變化的原因。職責(zé)過(guò)多滓窍,可能引起它變化的原因就越多卖词,這將導(dǎo)致職責(zé)依賴(lài),相互之間就產(chǎn)生影響吏夯,從而大大損傷其內(nèi)聚性和耦合度此蜈。通常意義下的單一職責(zé),就是指只有一種單一功能锦亦,不要為類(lèi)實(shí)現(xiàn)過(guò)多的功能點(diǎn)舶替,以保證實(shí)體只有一個(gè)引起它變化的原因。 專(zhuān)注杠园,是一個(gè)人優(yōu)良的品質(zhì)顾瞪;同樣的,單一也是一個(gè)類(lèi)的優(yōu)良設(shè)計(jì)。交雜不清的職責(zé)將使得代碼看起來(lái)特別別扭牽一發(fā)而動(dòng)全身陈醒,有失美感和必然導(dǎo)致丑陋的系統(tǒng)錯(cuò)誤風(fēng)險(xiǎn)惕橙。
開(kāi)放封閉原則(Open-Closed principle)
其核心思想是:軟件實(shí)體應(yīng)該是可擴(kuò)展的,而不可修改的钉跷。也就是弥鹦,對(duì)擴(kuò)展開(kāi)放,對(duì)修改封閉的爷辙。開(kāi)放封閉原則主要體現(xiàn)在兩個(gè)方面1彬坏、對(duì)擴(kuò)展開(kāi)放,意味著有新的需求或變化時(shí)膝晾,可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展栓始,以適應(yīng)新的情況。2血当、對(duì)修改封閉幻赚,意味著類(lèi)一旦設(shè)計(jì)完成,就可以獨(dú)立完成其工作臊旭,而不要對(duì)其進(jìn)行任何嘗試的修改落恼。 實(shí)現(xiàn)開(kāi)開(kāi)放封閉原則的核心思想就是對(duì)抽象編程,而不對(duì)具體編程离熏,因?yàn)槌橄笙鄬?duì)穩(wěn)定佳谦。讓類(lèi)依賴(lài)于固定的抽象,所以修改就是封閉的滋戳;而通過(guò)面向?qū)ο蟮睦^承和多態(tài)機(jī)制吠昭,又可以實(shí)現(xiàn)對(duì)抽象類(lèi)的繼承,通過(guò)覆寫(xiě)其方法來(lái)改變固有行為胧瓜,實(shí)現(xiàn)新的拓展方法,所以就是開(kāi)放的郑什。 “需求總是變化”沒(méi)有不變的軟件府喳,所以就需要用封閉開(kāi)放原則來(lái)封閉變化滿(mǎn)足需求,同時(shí)還能保持軟件內(nèi)部的封裝體系穩(wěn)定蘑拯,不被需求的變化影響钝满。
Liskov替換原則(Liskov-Substituion Principle)
其核心思想是:子類(lèi)必須能夠替換其基類(lèi)。這一思想體現(xiàn)為對(duì)繼承機(jī)制的約束規(guī)范申窘,只有子類(lèi)能夠替換基類(lèi)時(shí)弯蚜,才能保證系統(tǒng)在運(yùn)行期內(nèi)識(shí)別子類(lèi),這是保證繼承復(fù)用的基礎(chǔ)剃法。在父類(lèi)和子類(lèi)的具體行為中碎捺,必須嚴(yán)格把握繼承層次中的關(guān)系和特征,將基類(lèi)替換為子類(lèi),程序的行為不會(huì)發(fā)生任何變化收厨。同時(shí)晋柱,這一約束反過(guò)來(lái)則是不成立的,子類(lèi)可以替換基類(lèi)诵叁,但是基類(lèi)不一定能替換子類(lèi)雁竞。 Liskov替換原則,主要著眼于對(duì)抽象和多態(tài)建立在繼承的基礎(chǔ)上拧额,因此只有遵循了Liskov替換原則碑诉,才能保證繼承復(fù)用是可靠地。實(shí)現(xiàn)的方法是面向接口編程:將公共部分抽象為基類(lèi)接口或抽象類(lèi)侥锦,通過(guò)Extract Abstract Class进栽,在子類(lèi)中通過(guò)覆寫(xiě)父類(lèi)的方法實(shí)現(xiàn)新的方式支持同樣的職責(zé)。 Liskov替換原則是關(guān)于繼承機(jī)制的設(shè)計(jì)原則捎拯,違反了Liskov替換原則就必然導(dǎo)致違反開(kāi)放封閉原則泪幌。 Liskov替換原則能夠保證系統(tǒng)具有良好的拓展性,同時(shí)實(shí)現(xiàn)基于多態(tài)的抽象機(jī)制署照,能夠減少代碼冗余祸泪,避免運(yùn)行期的類(lèi)型判別。
依賴(lài)倒置原則(Dependecy-Inversion Principle)
其核心思想是:依賴(lài)于抽象建芙。具體而言就是高層模塊不依賴(lài)于底層模塊没隘,二者都同依賴(lài)于抽象;抽象不依賴(lài)于具體禁荸,具體依賴(lài)于抽象右蒲。 我們知道,依賴(lài)一定會(huì)存在于類(lèi)與類(lèi)赶熟、模塊與模塊之間瑰妄。當(dāng)兩個(gè)模塊之間存在緊密的耦合關(guān)系時(shí),最好的方法就是分離接口和實(shí)現(xiàn):在依賴(lài)之間定義一個(gè)抽象的接口使得高層模塊調(diào)用接口映砖,而底層模塊實(shí)現(xiàn)接口的定義间坐,以此來(lái)有效控制耦合關(guān)系,達(dá)到依賴(lài)于抽象的設(shè)計(jì)目標(biāo)邑退。 抽象的穩(wěn)定性決定了系統(tǒng)的穩(wěn)定性竹宋,因?yàn)槌橄笫遣蛔兊模蕾?lài)于抽象是面向?qū)ο笤O(shè)計(jì)的精髓地技,也是依賴(lài)倒置原則的核心蜈七。 依賴(lài)于抽象是一個(gè)通用的原則,而某些時(shí)候依賴(lài)于細(xì)節(jié)則是在所難免的莫矗,必須權(quán)衡在抽象和具體之間的取舍飒硅,方法不是一層不變的砂缩。依賴(lài)于抽象,就是對(duì)接口編程狡相,不要對(duì)實(shí)現(xiàn)編程梯轻。
接口隔離原則(Interface-Segregation Principle)
其核心思想是:使用多個(gè)小的專(zhuān)門(mén)的接口,而不要使用一個(gè)大的總接口尽棕。 具體而言喳挑,接口隔離原則體現(xiàn)在:接口應(yīng)該是內(nèi)聚的,應(yīng)該避免“胖”接口滔悉。一個(gè)類(lèi)對(duì)另外一個(gè)類(lèi)的依賴(lài)應(yīng)該建立在最小的接口上伊诵,不要強(qiáng)迫依賴(lài)不用的方法,這是一種接口污染回官。 接口有效地將細(xì)節(jié)和抽象隔離曹宴,體現(xiàn)了對(duì)抽象編程的一切好處,接口隔離強(qiáng)調(diào)接口的單一性歉提。而胖接口存在明顯的弊端笛坦,會(huì)導(dǎo)致實(shí)現(xiàn)的類(lèi)型必須完全實(shí)現(xiàn)接口的所有方法、屬性等苔巨;而某些時(shí)候版扩,實(shí)現(xiàn)類(lèi)型并非需要所有的接口定義,在設(shè)計(jì)上這是“浪費(fèi)”侄泽,而且在實(shí)施上這會(huì)帶來(lái)潛在的問(wèn)題礁芦,對(duì)胖接口的修改將導(dǎo)致一連串的客戶(hù)端程序需要修改,有時(shí)候這是一種災(zāi)難悼尾。在這種情況下柿扣,將胖接口分解為多個(gè)特點(diǎn)的定制化方法,使得客戶(hù)端僅僅依賴(lài)于它們的實(shí)際調(diào)用的方法闺魏,從而解除了客戶(hù)端不會(huì)依賴(lài)于它們不用的方法未状。 分離的手段主要有以下兩種:1、委托分離析桥,通過(guò)增加一個(gè)新的類(lèi)型來(lái)委托客戶(hù)的請(qǐng)求娩践,隔離客戶(hù)和接口的直接依賴(lài),但是會(huì)增加系統(tǒng)的開(kāi)銷(xiāo)烹骨。2、多重繼承分離材泄,通過(guò)接口多繼承來(lái)實(shí)現(xiàn)客戶(hù)的需求沮焕,這種方式是較好的。
以上就是5個(gè)基本的面向?qū)ο笤O(shè)計(jì)原則拉宗,它們就像面向?qū)ο蟪绦蛟O(shè)計(jì)中的金科玉律峦树,遵守它們可以使我們的代碼更加鮮活辣辫,易于復(fù)用,易于拓展魁巩,靈活優(yōu)雅急灭。不同的設(shè)計(jì)模式對(duì)應(yīng)不同的需求,而設(shè)計(jì)原則則代表永恒的靈魂谷遂,需要在實(shí)踐中時(shí)時(shí)刻刻地遵守葬馋。就如ARTHUR J.RIEL在那邊《OOD啟示錄》中所說(shuō)的:“你并不必嚴(yán)格遵守這些原則,違背它們也不會(huì)被處以宗教刑罰肾扰。但你應(yīng)當(dāng)把這些原則看做警鈴畴嘶,若違背了其中的一條,那么警鈴就會(huì)響起集晚〈懊酰”
設(shè)計(jì)模式分類(lèi)
一、GOF分類(lèi)法
1.創(chuàng)建型模式
前面講過(guò)偷拔,社會(huì)化的分工越來(lái)越細(xì)蒋院,自然在軟件設(shè)計(jì)方面也是如此,因此對(duì)象的創(chuàng)建和對(duì)象的使用分開(kāi)也就成為了必然趨勢(shì)莲绰。因?yàn)閷?duì)象的創(chuàng)建會(huì)消耗掉系統(tǒng)的很多資源欺旧,所以單獨(dú)對(duì)對(duì)象的創(chuàng)建進(jìn)行研究,從而能夠高效地創(chuàng)建對(duì)象就是創(chuàng)建型模式要探討的問(wèn)題钉蒲。這里有6個(gè)具體的創(chuàng)建型模式可供研究切端,它們分別是:
簡(jiǎn)單工廠(chǎng)模式(Simple Factory);
工廠(chǎng)方法模式(Factory Method)顷啼;
抽象工廠(chǎng)模式(Abstract Factory)踏枣;
創(chuàng)建者模式(Builder);
原型模式(Prototype)钙蒙;
單例模式(Singleton)茵瀑。
說(shuō)明:嚴(yán)格來(lái)說(shuō),簡(jiǎn)單工廠(chǎng)模式不是GoF總結(jié)出來(lái)的23種設(shè)計(jì)模式之一躬厌。
2.結(jié)構(gòu)型模式
在解決了對(duì)象的創(chuàng)建問(wèn)題之后马昨,對(duì)象的組成以及對(duì)象之間的依賴(lài)關(guān)系就成了開(kāi)發(fā)人員關(guān)注的焦點(diǎn),因?yàn)槿绾卧O(shè)計(jì)對(duì)象的結(jié)構(gòu)扛施、繼承和依賴(lài)關(guān)系會(huì)影響到后續(xù)程序的維護(hù)性鸿捧、代碼的健壯性、耦合性等疙渣。對(duì)象結(jié)構(gòu)的設(shè)計(jì)很容易體現(xiàn)出設(shè)計(jì)人員水平的高低匙奴,這里有7個(gè)具體的結(jié)構(gòu)型模式可供研究,它們分別是:
外觀模式(Facade)妄荔;
適配器模式(Adapter)泼菌;
代理模式(Proxy)谍肤;
裝飾模式(Decorator);
橋模式(Bridge)哗伯;
組合模式(Composite)荒揣;
享元模式(Flyweight)。
3.行為型模式
在對(duì)象的結(jié)構(gòu)和對(duì)象的創(chuàng)建問(wèn)題都解決了之后焊刹,就剩下對(duì)象的行為問(wèn)題了系任,如果對(duì)象的行為設(shè)計(jì)的好,那么對(duì)象的行為就會(huì)更清晰伴澄,它們之間的協(xié)作效率就會(huì)提高赋除,這里有11個(gè)具體的行為型模式可供研究,它們分別是:
模板方法模式(Template Method)非凌;
觀察者模式(Observer)举农;
狀態(tài)模式(State);
策略模式(Strategy)敞嗡;
職責(zé)鏈模式(Chain of Responsibility)颁糟;
命令模式(Command);
訪(fǎng)問(wèn)者模式(Visitor)喉悴;
調(diào)停者模式(Mediator)棱貌;
備忘錄模式(Memento);
迭代器模式(Iterator)箕肃;
解釋器模式(Interpreter)婚脱。
二、封裝角度模式分類(lèi)
1.組件協(xié)作
Template Method
Strategy
Observer/Event
2.單一職責(zé)
Decorator
Bridge
3.對(duì)象創(chuàng)建
Factory Method
Abstract Factory
Prototype
Builder
4.對(duì)象性能
Singleton
Flyweight
5.接口隔離
Facade
Proxy
Mediator
Adapter
6.狀態(tài)改變
Mememto
State
7.數(shù)據(jù)結(jié)構(gòu)
Composite
Iterator
Chain of Responsibility
8.行為改變
Command
Visitor
9.領(lǐng)域問(wèn)題
Interpreter
重構(gòu)獲得模式
不宜一開(kāi)始就用設(shè)計(jì)模式勺像,而是對(duì)代碼進(jìn)行重構(gòu)以獲得良好的設(shè)計(jì)障贸。
重構(gòu)的關(guān)鍵技法
1.靜態(tài)綁定->動(dòng)態(tài)綁定
2.早綁定->晚綁定
3.繼承->組合
4.編譯時(shí)依賴(lài)->運(yùn)行時(shí)依賴(lài)
5.緊耦合->松耦合
下面分別介紹23個(gè)模式。