編程設(shè)計(jì)模式
六大基本原則
總原則:開閉原則(Open Close Principle,OCP)
開:對拓展開放莹捡,允許拓展鬼吵。
閉:對修改關(guān)閉,禁止修改篮赢。
其含義在于拓展程序時(shí)而柑,不要修改原有的代碼文捶,而是僅拓展。這是為了使程序的拓展性更好媒咳,易于維護(hù)和升級粹排,當(dāng)然,這樣會(huì)導(dǎo)致代碼臃腫涩澡,但利遠(yuǎn)遠(yuǎn)大于弊顽耳。
主要思想:在于使用接口和抽象類。
1:單一職責(zé)原則
每個(gè)類應(yīng)該實(shí)現(xiàn)單一的職責(zé)妙同,若存在不同種修改的原因射富,應(yīng)該將對象進(jìn)行拆分。
2:里氏替換原則(Liskov Substitution Principle粥帚,LSP) /* 子可替父胰耗,正常工作 */
面向?qū)ο笤O(shè)計(jì)的基本原則之一。其主要思想在于任何基類可以出現(xiàn)的地方芒涡,子類一定可以出現(xiàn)柴灯。其作為開閉原則的補(bǔ)充,描述了對實(shí)現(xiàn)抽象化的具體步驟的規(guī)范费尽。
只有當(dāng)派生類可以替換基類赠群,且軟件功能不受影響時(shí),基類才能真正被復(fù)用旱幼。當(dāng)然查描,衍生類能夠在基類的基礎(chǔ)上增加新的行為。
3:依賴倒轉(zhuǎn)原則(Dependency Inversion Principle柏卤,DIP) /* 接口交互 冬三,不看具體 */
作為開閉原則的基礎(chǔ),在面向接口編程時(shí)缘缚,依賴于抽象類长豁,而非具體的實(shí)現(xiàn)類。寫代碼中忙灼,用到具體類時(shí),不與具體類進(jìn)行交互钝侠,而是與其接口進(jìn)行交互该园。
4:接口隔離原則(Interface Segregation Principle,ISP) /* 細(xì)分接口帅韧,功能純粹 */
每個(gè)接口不存在子類不需要里初,但必須實(shí)現(xiàn)的方法。如果有忽舟,就要將接口拆分双妨。使用多個(gè)隔離接口淮阐,比使用單個(gè)(合多為一)接口更好。
5:迪米特原則(最少知道原則)(Demeter Principle刁品,DP)
一個(gè)類A泣特,對要用到的類B的信息(如作為其成員變量),知道的越少越好挑随。無論對類B本身有多復(fù)雜状您,都應(yīng)該只使用public來使用它,將其復(fù)雜的邏輯封裝在方法的內(nèi)部兜挨。這樣在變動(dòng)時(shí)膏孟,對類A的影響會(huì)最小。
另一個(gè)陳述方式是:只與直接的朋友通信拌汇。
類之間只要有耦合關(guān)系柒桑,就叫朋友關(guān)系。耦合分為依賴噪舀、關(guān)聯(lián)魁淳、聚合、組合等傅联。若類B作為類A成員變量先改、方法參數(shù)、方法返回值蒸走,則為直接朋友仇奶;若作為函數(shù)內(nèi)局部變量、臨時(shí)變量則非直接朋友比驻。陌生的類该溯,不要作為局部變量出現(xiàn)在類中。
6:合成復(fù)用原則(Composite Reuse Principle别惦,CRP)
盡量首先使用合成/聚合的方式狈茉,而不是使用繼承。先考慮將類作為成員變量掸掸、函數(shù)參數(shù)氯庆,而不是先考慮繼承。
java的23種設(shè)計(jì)模式
創(chuàng)建型模式扰付,共五種:工廠方法模式堤撵、抽象工廠模式、單例模式羽莺、建造者模式实昨、原型模式。
結(jié)構(gòu)型模式盐固,共七種:適配器模式荒给、裝飾器模式丈挟、代理模式、外觀模式志电、橋接模式曙咽、組合模式、享元模式溪北。
行為型模式桐绒,共十一種:策略模式、模板方法模式之拨、觀察者模式茉继、迭代子模式、責(zé)任鏈模式蚀乔、命令模式烁竭、備忘錄模式、狀態(tài)模式吉挣、訪問者模式派撕、中介者模式、解釋器模式睬魂。
創(chuàng)建型模式
概述:用什么方法創(chuàng)建類和對象终吼。
包含:工廠方法模式、抽象工廠模式氯哮、單例模式际跪、原型模式、建造者模式喉钢。
0.簡單工廠模式(不屬于23種之一)
以其姆打,可以延伸出更好的方法,所以先探討這個(gè)肠虽。適用于:大量的產(chǎn)品(接口的具體類)需要?jiǎng)?chuàng)建幔戏。
三種簡單工廠模式:普通、多方法税课、靜態(tài)方法闲延。
以下是在測試Test類中,調(diào)用了工廠類和接口類韩玩。以接口類作為基類垒玲,標(biāo)識符指向?qū)崿F(xiàn)對象:工廠類中函數(shù)(produce)返回的接口實(shí)例。
Test類中 | 普通 | 多方法 | 靜態(tài)方法 |
---|---|---|---|
接口類(負(fù)責(zé)指向具體對象) | 需要實(shí)例化啸如。指向工廠produce返回對象。 | 需要實(shí)例化氮惯。指向工廠produce返回對象叮雳。 | 需要實(shí)例化想暗。指向工廠produce返回對象。 |
工廠類(生成接口實(shí)例) | 需要實(shí)例化帘不。一個(gè)produce函數(shù)说莫。需要參數(shù),來進(jìn)行對接口的選擇寞焙〈⑾粒可能要具備 | 需要實(shí)例化。多個(gè)produceX函數(shù)捣郊。每個(gè)返回不同的接口實(shí)現(xiàn)對象辽狈。 | 不需要實(shí)例化。也是多個(gè)produceX呛牲。負(fù)責(zé)返回單一的接口實(shí)現(xiàn)對象刮萌,但其為靜態(tài)函數(shù)。 |
可以看出娘扩,靜態(tài)工廠方法着茸,比前兩種更加優(yōu)越。其不需要傳入?yún)?shù)琐旁,所以不必考慮參數(shù)不符合的糾錯(cuò)涮阔。比多方法又不需要實(shí)例化。
1.工廠方法模式(以下屬于23種)
作為簡單工廠的最終實(shí)現(xiàn)灰殴,其根據(jù)代碼 “不修改敬特,只拓展” 的原則:
①有工廠接口。派生出多個(gè)具體工廠類验懊,每廠只生產(chǎn)一種對象擅羞。
②有產(chǎn)品接口(如Sender,具體實(shí)現(xiàn)為EmailSender义图、SmsSender等)减俏。派生出多個(gè)具體產(chǎn)品類。每個(gè)具體產(chǎn)品都有唯一工廠創(chuàng)建碱工。
當(dāng)拓展時(shí)娃承,新建一個(gè)產(chǎn)品類,就對應(yīng)新建一個(gè)工廠類怕篷。不修改历筝,只拓展。
反思:這種思想會(huì)導(dǎo)致大量臃腫的代碼廊谓,應(yīng)配合其他方法使用梳猪,而非獨(dú)一。
2.抽象工廠模式
工廠方法模式:更像現(xiàn)實(shí)中工廠的流水線蒸痹,而非工廠春弥。因?yàn)橐粋€(gè)具體工廠類呛哟,只能生產(chǎn)一個(gè)產(chǎn)品。
抽象工廠模式:更像現(xiàn)實(shí)中工廠匿沛。其有多個(gè)抽象工廠扫责,每個(gè)工廠,能生產(chǎn)一個(gè)接口下的不同具體實(shí)例逃呼。
對比 | 工廠接口 | 具體工廠 | 產(chǎn)品接口 | 具體產(chǎn)品 |
---|---|---|---|---|
工廠方法模式 | 1個(gè) | k個(gè) | 1個(gè) | k個(gè) |
抽象方法模式 | n個(gè) | n或n*k個(gè) | k個(gè) | n*k個(gè) |
抽象方法模式中鳖孤,每個(gè)具體工廠可以生產(chǎn)一個(gè)產(chǎn)品(簡單工廠模式),或者生產(chǎn)多個(gè)產(chǎn)品(工廠方法模式)抡笼。
當(dāng)然苏揣,如采用工廠方法模式(不修改,僅拓展)蔫缸,會(huì)導(dǎo)致很多的類腿准,采用簡單工廠模式會(huì)更加簡潔(修改并拓展)。
3.單例模式
單例對象是一種常用的設(shè)計(jì)模式拾碌⊥麓校可保證在jvm中,每個(gè)對象實(shí)例僅存在一個(gè)(一個(gè)類只可以產(chǎn)生同一個(gè)對象)校翔。
class A{}
public class Singleton {
private Singleton() {};
public static Singleton getInstance() {
return SingleFactory.instance;
}
private static class SingleFactory{
private static Singleton instance =new Singleton();
};
public static void main(String [] args) {
Singleton x =Singleton.getInstance();
Singleton y=Singleton.getInstance();
System.out.println("x=y ? "+(x==y));/*使用了單例模式弟跑,x、y指向同一實(shí)例:輸出true*/
A a = new A();
A a1 = new A();
System.out.println("a=a1 ? "+(a==a1));/*正常實(shí)例化的兩個(gè)對象防症,a孟辑、a1指向不同實(shí)例:輸出 false8*/
}
}
優(yōu)點(diǎn):
①某些類尤其是大型類,當(dāng)其頻繁的創(chuàng)建時(shí)蔫敲,對系統(tǒng)開銷很大饲嗽。
②省去了new操作符,降低了系統(tǒng)內(nèi)存的使用頻率奈嘿,減輕GC(垃圾回收)壓力貌虾。
③某些類,如交易所的核心交易引擎裙犹,只能有一個(gè)存在尽狠,不能創(chuàng)建多個(gè),否則會(huì)出大錯(cuò)叶圃。使用單例可以避免出現(xiàn)這些麻煩袄膏。
實(shí)現(xiàn):
①將類構(gòu)造函數(shù)變成私有,禁止自動(dòng)構(gòu)造掺冠。
②提供一個(gè)getInstance()方法沉馆,返回該類對象。
③getInstance()函數(shù)中,對獲取對象的方法斥黑,要注意多線程出錯(cuò)問題闽瓢,可采用synchronized進(jìn)行必要鎖定。
實(shí)例可以看:https://www.cnblogs.com/onetwo/p/9933417.html
4.建造者模式
Builder和Factory不同之處心赶,在于Builder可以將多種類型,復(fù)合起來:其內(nèi)部可以包含一個(gè)或多個(gè)List<Interface/abstract>缺猛。
一個(gè)List<Interface/abstract>:又可以包含多個(gè)不同的具體派生類缨叫、實(shí)現(xiàn)類實(shí)例。
如同翁凱老師在java課中講的FoxAndRabbit實(shí)例荔燎,F(xiàn)iled類中耻姥,包含了Cell [ ] [ ] Animals的數(shù)組。里面可以存放狐貍有咨、兔子或空琐簇。動(dòng)物都implements (interface) Cell的。
5.原型模式(Prototype)
概述:用復(fù)制clone()代替new座享,在類中有大量對象時(shí)婉商,復(fù)制比new一個(gè)對象更高效。
原型模式通常適用于以下場景渣叛。
- 對象之間相同或相似丈秩,即只是個(gè)別的幾個(gè)屬性不同的時(shí)候。
- 對象的創(chuàng)建過程比較麻煩淳衙,但復(fù)制比較簡單的時(shí)候
實(shí)現(xiàn):
①該原型類需要implements Cloneable蘑秽。
②重寫clone()函數(shù),通常直接return super.clone();
③測試中箫攀,對象不新建肠牲,而是復(fù)制。 x != x.clone();
淺拷貝:拷貝時(shí)創(chuàng)建一個(gè)新的對象靴跛,對象中的基本數(shù)據(jù)類型會(huì)復(fù)制缀雳,而對屬性是引用類型(如對象成員變量)不會(huì)創(chuàng)建新的對象,而是使用與之前的對象指向同一個(gè)內(nèi)存地址汤求。即:
x!=x.clone();
x.b == x.clone().b; /* b為class B類型的靜態(tài)成員變量 */
深拷貝:拷貝時(shí)創(chuàng)建一個(gè)新的對象俏险,并且所有屬性都是新對象(指向新的內(nèi)存地址)
結(jié)構(gòu)型模式
概述:用什么方法將類和對象布局(組合復(fù)用)成更大的結(jié)構(gòu)。
分為:類結(jié)構(gòu)型模式和對象結(jié)構(gòu)型模式扬绪。前者采用繼承機(jī)制來組織接口和類竖独,后者釆用組合或聚合來組合對象。
由于組合關(guān)系或聚合關(guān)系挤牛,比類的繼承關(guān)系耦合性低莹痢,所以通常對象結(jié)構(gòu)型模式具備更強(qiáng)靈活性。
1.適配器模式
在軟件設(shè)計(jì)中可能出現(xiàn):需要開發(fā)的具有某種業(yè)務(wù)功能的組件在現(xiàn)有的組件庫中已經(jīng)存在,但它們與當(dāng)前系統(tǒng)的接口規(guī)范不兼容竞膳,如果重新開發(fā)這些組件成本又很高航瞭,這時(shí)用適配器模式能很好地解決這些問題。
分為:類適配器坦辟、對象適配器(更多用)刊侯。
主要優(yōu)點(diǎn):
- 客戶端通過適配器可以透明地調(diào)用目標(biāo)接口。
- 復(fù)用了現(xiàn)存的類锉走,程序員不需要修改原有代碼而重用現(xiàn)有的適配者類滨彻。
- 將目標(biāo)類和適配者類解耦,解決了目標(biāo)類和適配者類接口不一致的問題挪蹭。
其缺點(diǎn)是:對類適配器來說亭饵,更換適配器的實(shí)現(xiàn)過程比較復(fù)雜。
方式:如main函數(shù)中需要調(diào)用request()函數(shù)梁厉,而數(shù)據(jù)庫里有個(gè)可以實(shí)現(xiàn)這個(gè)功能的函數(shù)辜羊,但其接口為SpecialRequest(),此時(shí)词顾,我們將SpecialReaquest()函數(shù)進(jìn)行包裝八秃,用繼承或包含類對象的方式,給出一個(gè)request接口肉盹,里面調(diào)用SpecialRequest()喜德。
其他模式都是從適配器模式,延伸出來的垮媒。
2.裝飾模式
對已有的類舍悯,進(jìn)行功能拓展。
方法:建立一個(gè)新類睡雇,與原有類要implements same interfaces萌衬,然后重寫方法,方法中它抱,可以調(diào)用已有類的同名方法秕豫,并對其拓展。
3.代理模式(Proxy)
對某個(gè)類A進(jìn)行代理观蓄,用新的代理類B接口來替換其接口混移,當(dāng)需要對A進(jìn)行訪問時(shí),不直接訪問A侮穿,而是通過B訪問A歌径。
是為了對被代理類,進(jìn)行保護(hù)亲茅,如訪問遠(yuǎn)程對象很大(視頻回铛、大圖)狗准,或服務(wù)器中的數(shù)據(jù)庫,出于安全不能讓客戶端直接訪問茵肃,而是通過中間類腔长。
主要優(yōu)點(diǎn):
- 代理模式在客戶端與目標(biāo)對象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對象的作用;
- 代理對象可以擴(kuò)展目標(biāo)對象的功能验残; (拓展不修改)
- 代理模式能將客戶端與目標(biāo)對象分離捞附,在一定程度上降低了系統(tǒng)的耦合度;
主要缺點(diǎn):
- 在客戶端和目標(biāo)對象之間增加一個(gè)代理對象您没,會(huì)造成請求處理速度變慢故俐;
- 增加了系統(tǒng)的復(fù)雜度;
應(yīng)用場景:
- 遠(yuǎn)程代理:這種方式通常是為了隱藏目標(biāo)對象存在于不同地址空間的事實(shí)紊婉,方便客戶端訪問。例如辑舷,用戶申請某些網(wǎng)盤空間時(shí)喻犁,會(huì)在用戶的文件系統(tǒng)中建立一個(gè)虛擬的硬盤,用戶訪問虛擬硬盤時(shí)實(shí)際訪問的是網(wǎng)盤空間何缓。
- 虛擬代理:這種方式通常用于要?jiǎng)?chuàng)建的目標(biāo)對象開銷很大時(shí)肢础。例如,下載一幅很大的圖像需要很長時(shí)間碌廓,因某種計(jì)算比較復(fù)雜而短時(shí)間無法完成传轰,這時(shí)可以先用小比例的虛擬代理替換真實(shí)的對象,消除用戶對服務(wù)器慢的感覺谷婆。
- 安全代理:這種方式通常用于控制不同種類客戶對真實(shí)對象的訪問權(quán)限慨蛙。
- 智能指引:主要用于調(diào)用目標(biāo)對象時(shí),代理附加一些額外的處理功能纪挎。例如期贫,增加計(jì)算真實(shí)對象的引用次數(shù)的功能,這樣當(dāng)該對象沒有被引用時(shí)异袄,就可以自動(dòng)釋放它通砍。
- 延遲加載:指為了提高系統(tǒng)的性能,延遲對目標(biāo)的加載烤蜕。例如封孙,Hibernate 中就存在屬性的延遲加載和關(guān)聯(lián)表的延時(shí)加載。
4.外觀模式(Facade)
迪米特原則(最少知道原則)的具體實(shí)現(xiàn)讽营。將多個(gè)相關(guān)聯(lián)類虎忌,組合到一個(gè)類Conbine中(以成員變量等形式)。Conbine類提供統(tǒng)一的接口橱鹏,對每個(gè)組件類統(tǒng)一操作呐籽,降低了客戶端和組件類的耦合性锋勺,也降低了組件類之間互相關(guān)聯(lián)的耦合性。
舉例:Computer類包含了Cpu類狡蝶、Memory類庶橱、Disk類。Computer::start中贪惹,會(huì)調(diào)用組件類的start函數(shù)苏章。
應(yīng)用場景
對分層結(jié)構(gòu)系統(tǒng)構(gòu)建時(shí),使用外觀模式定義子系統(tǒng)中每層的入口點(diǎn)可以簡化子系統(tǒng)之間的依賴關(guān)系奏瞬。
當(dāng)一個(gè)復(fù)雜系統(tǒng)的子系統(tǒng)很多時(shí)枫绅,外觀模式可以為系統(tǒng)設(shè)計(jì)一個(gè)簡單的接口供外界訪問。
當(dāng)客戶端與多個(gè)子系統(tǒng)之間存在很大的聯(lián)系時(shí)硼端,引入外觀模式可將它們分離并淋,從而提高子系統(tǒng)的獨(dú)立性和可移植性。
限制:
不能很好地限制客戶使用子系統(tǒng)類珍昨。
增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼县耽,違背了“開閉原則”。
5.橋接模式(Bridge)
概述:用組合關(guān)系代替繼承關(guān)系镣典。
優(yōu)點(diǎn):
- 由于抽象與實(shí)現(xiàn)分離兔毙,所以擴(kuò)展能力強(qiáng);
- 其實(shí)現(xiàn)細(xì)節(jié)對客戶透明兄春。
缺點(diǎn):
由于聚合關(guān)系建立在抽象層澎剥,要求開發(fā)者針對抽象化進(jìn)行設(shè)計(jì)與編程,這增加了系統(tǒng)的理解與設(shè)計(jì)難度赶舆。
如:對于女士包:顏色哑姚、型號、挎包芜茵、錢包蜻懦。
不是對女士包進(jìn)行一個(gè)抽象,具體實(shí)現(xiàn)時(shí)包含各自的款型和顏色夕晓。而是:提出顏色類宛乃、包型類(派生出錢包、挎包)蒸辆。對于每個(gè)具體的包征炼,會(huì)包含一個(gè)顏色類的實(shí)體。
用組合代替了繼承躬贡。
應(yīng)用場景:
- 當(dāng)一個(gè)類存在兩個(gè)獨(dú)立變化的維度谆奥,且這兩個(gè)維度都需要進(jìn)行擴(kuò)展時(shí)。
- 當(dāng)一個(gè)系統(tǒng)不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)急劇增加時(shí)拂玻。
- 當(dāng)一個(gè)系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性時(shí)酸些。
6.組合模式(Composite)
概述:將對象組合成形如tree的關(guān)系宰译。如樹結(jié)構(gòu)便是用了組合模式。(部分-整體形式)
主要優(yōu)點(diǎn):
- 組合模式使得客戶端代碼可以一致地處理單個(gè)對象和組合對象魄懂,無須關(guān)心自己處理的是單個(gè)對象沿侈,還是組合對象,這簡化了客戶端代碼市栗;
- 更容易在組合體內(nèi)加入新的對象缀拭,客戶端不會(huì)因?yàn)榧尤肓诵碌膶ο蠖脑创a,滿足“開閉原則”填帽;
主要缺點(diǎn):
設(shè)計(jì)較復(fù)雜蛛淋,客戶端需要花更多時(shí)間理清類之間的層次關(guān)系;
不容易限制容器中的構(gòu)件篡腌;
不容易用繼承的方法來增加構(gòu)件的新功能褐荷;
7.享元模式(Flyweight)
概述:當(dāng)需要多次生成對象,且他們僅有部分不同(如五子棋中的棋子嘹悼,顯示器中的像素點(diǎn))叛甫。建立共享對象,使新建對象的相同部分指向其對象中元素绘迁。(通常與工廠模式搭配)
優(yōu)點(diǎn):相同對象只保存一份。降低數(shù)量卒密,降低內(nèi)存壓力缀台。
缺點(diǎn):
- 為使對象共享,需使對象中區(qū)別元素可視化哮奇,外部可訪問膛腐,增加程序復(fù)雜性。
- 讀取該模式下的外部狀態(tài)鼎俘,會(huì)使運(yùn)行時(shí)間稍微變長哲身。
行為型模式
概述:行為型模式用于描述程序在運(yùn)行時(shí)復(fù)雜的流程控制,即描述多個(gè)類或?qū)ο笾g怎樣相互協(xié)作共同完成單個(gè)對象都無法單獨(dú)完成的任務(wù)贸伐,它涉及算法與對象間職責(zé)的分配勘天。
行為型模式分為類行為模式和對象行為模式(*),前者采用繼承機(jī)制來在類間分派行為捉邢,后者采用組合或聚合在對象間分配行為脯丝。
示意圖
1.策略模式(Strategy)
概述:可理解為選擇模式。一個(gè)類中伏伐,針對某一個(gè)函數(shù)宠进,可以選擇不同的對象來實(shí)現(xiàn)(同一個(gè)基類或接口),通過輸入的參數(shù)來確定藐翎。如輸出“x+y”材蹬、“x*y”实幕,可先解析出操作符,然后調(diào)用不同方法來實(shí)現(xiàn)堤器;還有現(xiàn)實(shí)中的超市活動(dòng)昆庇,可以通過送積分、送現(xiàn)金等方法吼旧。
主要優(yōu)點(diǎn):
- 多重條件語句不易維護(hù)燃观,而使用策略模式可以避免使用多重條件語句。
- 策略模式提供了一系列的可供重用的算法族盗棵,恰當(dāng)使用繼承可以把算法族的公共代碼轉(zhuǎn)移到父類里面缘挽,從而避免重復(fù)的代碼。
- 策略模式可以提供相同行為的不同實(shí)現(xiàn)员串,客戶可以根據(jù)不同時(shí)間或空間要求選擇不同的勇哗。
- 策略模式提供了對開閉原則的完美支持,可以在不修改原代碼的情況下寸齐,靈活增加新算法欲诺。
- 策略模式把算法的使用放到環(huán)境類中,而算法的實(shí)現(xiàn)移到具體策略類中渺鹦,實(shí)現(xiàn)了二者的分離扰法。
主要缺點(diǎn):
- 客戶端必須理解所有策略算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴悺?/li>
- 策略模式造成很多的策略類毅厚。
2.模板方法模式(Template Method)
概述:一個(gè)抽象類塞颁,很多派生類。通過對抽象類的調(diào)用吸耿,使用派生類的重載方法祠锣。
3.觀察者模式(Obsever)
概述:指多個(gè)對象間存在一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí)咽安,所有依賴于它的對象都得到通知并被自動(dòng)更新伴网。這種模式有時(shí)又稱作發(fā)布-訂閱模式、模型-視圖模式妆棒,它是對象行為型模式澡腾。
如同Excel中,數(shù)據(jù)變化糕珊,會(huì)導(dǎo)致示意圖(折線圖蛋铆、餅狀圖)發(fā)生變化。
包含此模式以后的四個(gè)模式放接,都是類與類(對象)之間的關(guān)系刺啦,不涉及繼承。
實(shí)現(xiàn):
- 抽象主題角色:也叫抽象目標(biāo)類纠脾,它提供了一個(gè)用于保存觀察者對象的聚集類和增加玛瘸、刪除觀察者對象的方法蜕青,以及通知所有觀察者的抽象方法。(Subject)
- 具體主題角色:也叫具體目標(biāo)類糊渊,它實(shí)現(xiàn)抽象目標(biāo)中的通知方法右核,當(dāng)具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),通知所有注冊過的觀察者對象渺绒。(Concrete Subject)
- 抽象觀察者角色:它是一個(gè)抽象類或接口贺喝,它包含了一個(gè)更新自己的抽象方法,當(dāng)接到具體主題的更改通知時(shí)被調(diào)用宗兼。(Observer)
- 具體觀察者角色:實(shí)現(xiàn)抽象觀察者中定義的抽象方法躏鱼,以便在得到目標(biāo)的更改通知時(shí)更新自身的狀態(tài)。(Concrete Observer)
4.迭代器模式(Iterator)
概述:建立一個(gè)迭代器對象來管理數(shù)據(jù)殷绍。
它在客戶訪問類與聚合類之間插入一個(gè)迭代器染苛,這分離了聚合對象與其遍歷行為,對客戶也隱藏了其內(nèi)部細(xì)節(jié)主到,且滿足“單一職責(zé)原則”和“開閉原則”茶行,如 Java 中的 Collection、List登钥、Set畔师、Map 等都包含了迭代器。
主要優(yōu)點(diǎn):
- 訪問一個(gè)聚合對象的內(nèi)容而無須暴露它的內(nèi)部表示牧牢。
- 遍歷任務(wù)交由迭代器完成看锉,這簡化了聚合類。
- 它支持以不同方式遍歷一個(gè)聚合结执,甚至可以自定義迭代器的子類以支持新的遍歷度陆。
- 增加新的聚合類和迭代器類都很方便艾凯,無須修改原有代碼献幔。
- 封裝性良好,為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口趾诗。
主要缺點(diǎn):增加了類的個(gè)數(shù)蜡感,這在一定程度上增加了系統(tǒng)的復(fù)雜性。
迭代器模式主要包含以下角色恃泪。
- 抽象聚合角色:定義存儲郑兴、添加、刪除聚合對象以及創(chuàng)建迭代器對象的接口贝乎。(Aggregate)
- 具體聚合角色:實(shí)現(xiàn)抽象聚合類情连,返回一個(gè)具體迭代器的實(shí)例。(ConcreteAggregate)
- 抽象迭代器角色:定義訪問和遍歷聚合元素的接口览效,通常包含 hasNext()却舀、first()虫几、next() 等方法。(Iterator)
- 具體迭代器角色:實(shí)現(xiàn)抽象迭代器接口中所定義的方法挽拔,完成對聚合對象的遍歷辆脸,記錄遍歷的當(dāng)前位置。(Concretelterator)
5.責(zé)任鏈模式(Chain of Responsibility)
概述:為了避免請求發(fā)送者與多個(gè)請求處理者耦合在一起螃诅,將所有請求的處理者通過前一對象記住其下一個(gè)對象的引用而連成一條鏈;當(dāng)有請求發(fā)生時(shí),可將請求沿著這條鏈傳遞,直到有對象處理它為止袍镀。
在責(zé)任鏈模式中,客戶只需要將請求發(fā)送到責(zé)任鏈上即可叉存,無須關(guān)心請求的處理細(xì)節(jié)和請求的傳遞過程,所以責(zé)任鏈將請求的發(fā)送者和請求的處理者解耦了练俐。
責(zé)任鏈模式是一種對象行為型模式。
主要優(yōu)點(diǎn):
- 降低了對象之間的耦合度连霉。該模式使得一個(gè)對象無須知道到底是哪一個(gè)對象處理其請求以及鏈的結(jié)構(gòu)歉井,發(fā)送者和接收者也無須擁有對方的明確信息。
- 增強(qiáng)了系統(tǒng)的可擴(kuò)展性。可以根據(jù)需要增加新的請求處理類诈乒,滿足開閉原則。
- 增強(qiáng)了給對象指派職責(zé)的靈活性荆陆。當(dāng)工作流程發(fā)生變化滩届,可以動(dòng)態(tài)地改變鏈內(nèi)的成員或者調(diào)動(dòng)它們的次序,也可動(dòng)態(tài)地新增或者刪除責(zé)任。
- 責(zé)任鏈簡化了對象之間的連接帜消。每個(gè)對象只需保持一個(gè)指向其后繼者的引用棠枉,不需保持其他所有處理者的引用,這避免了使用眾多的 if 或者 if···else 語句泡挺。
- 責(zé)任分擔(dān)辈讶。每個(gè)類只需要處理自己該處理的工作,不該處理的傳遞給下一個(gè)對象完成娄猫,明確各類的責(zé)任范圍贱除,符合類的單一職責(zé)原則。
主要缺點(diǎn):
- 不能保證每個(gè)請求一定被處理媳溺。由于一個(gè)請求沒有明確的接收者月幌,所以不能保證它一定會(huì)被處理,該請求可能一直傳到鏈的末端都得不到處理悬蔽。
- 對比較長的職責(zé)鏈扯躺,請求的處理可能涉及多個(gè)處理對象,系統(tǒng)性能將受到一定影響蝎困。
- 職責(zé)鏈建立的合理性要靠客戶端來保證录语,增加了客戶端的復(fù)雜性,可能會(huì)由于職責(zé)鏈的錯(cuò)誤設(shè)置而導(dǎo)致系統(tǒng)出錯(cuò)禾乘,如可能會(huì)造成循環(huán)調(diào)用钦无。
6.命令模式(Command)
概述:將一個(gè)請求封裝為一個(gè)對象,使發(fā)出請求和執(zhí)行請求的對象分割開盖袭。這樣兩者之間通過命令對象進(jìn)行溝通失暂,這樣方便將命令對象進(jìn)行儲存、傳遞鳄虱、調(diào)用弟塞、增加與管理。
在軟件開發(fā)系統(tǒng)中拙已,常常出現(xiàn)“方法的請求者”與“方法的實(shí)現(xiàn)者”之間存在緊密的耦合關(guān)系决记。這不利于軟件功能的擴(kuò)展與維護(hù)。例如倍踪,想對行為進(jìn)行“撤銷系宫、重做、記錄”等處理都很不方便建车,因此“如何將方法的請求者與方法的實(shí)現(xiàn)者解耦扩借?”變得很重要,命令模式能很好地解決這個(gè)問題缤至。
主要優(yōu)點(diǎn):
- 降低系統(tǒng)的耦合度潮罪。命令模式能將調(diào)用操作的對象與實(shí)現(xiàn)該操作的對象解耦。
- 增加或刪除命令非常方便。采用命令模式增加與刪除命令不會(huì)影響其他類嫉到,它滿足“開閉原則”沃暗,對擴(kuò)展比較靈活。
- 可以實(shí)現(xiàn)宏命令何恶。命令模式可以與組合模式結(jié)合孽锥,將多個(gè)命令裝配成一個(gè)組合命令,即宏命令细层。
- 方便實(shí)現(xiàn) Undo 和 Redo 操作忱叭。命令模式可以與后面介紹的備忘錄模式結(jié)合,實(shí)現(xiàn)命令的撤銷與恢復(fù)今艺。
主要缺點(diǎn):
可能產(chǎn)生大量具體命令類韵丑。因?yàn)橛?jì)對每一個(gè)具體操作都需要設(shè)計(jì)一個(gè)具體命令類,這將增加系統(tǒng)的復(fù)雜性虚缎。
7.備忘錄模式(Momento)
概述:在不破壞封裝性的前提下撵彻,捕獲一個(gè)對象的內(nèi)部狀態(tài),并在該對象之外保存這個(gè)狀態(tài)实牡,以便以后當(dāng)需要時(shí)能將該對象恢復(fù)到原先保存的狀態(tài)陌僵。該模式又叫快照模式〈次耄“備份-恢復(fù)”模式
每個(gè)人都有犯錯(cuò)誤的時(shí)候碗短,都希望有種“后悔藥”能彌補(bǔ)自己的過失,讓自己重新開始题涨,但現(xiàn)實(shí)是殘酷的偎谁。在計(jì)算機(jī)應(yīng)用中,客戶同樣會(huì)常常犯錯(cuò)誤纲堵,能否提供“后悔藥”給他們呢巡雨?當(dāng)然是可以的,而且是有必要的席函。這個(gè)功能由“備忘錄模式”來實(shí)現(xiàn)铐望。
其實(shí)很多應(yīng)用軟件都提供了這項(xiàng)功能,如 Word茂附、記事本正蛙、Photoshop、Eclipse 等軟件在編輯時(shí)按 Ctrl+Z 組合鍵時(shí)能撤銷當(dāng)前操作营曼,使文檔恢復(fù)到之前的狀態(tài)乒验;還有在 IE 中的后退鍵、數(shù)據(jù)庫事務(wù)管理中的回滾操作溶推、玩游戲時(shí)的中間結(jié)果存檔功能徊件、數(shù)據(jù)庫與操作系統(tǒng)的備份操作、棋類游戲中的悔棋功能等都屬于這類蒜危。
備忘錄模式是一種對象行為型模式虱痕。
類 | 起源類 | 備忘錄類 | 存儲備忘錄類 |
---|---|---|---|
功能 | 提供一個(gè)可恢復(fù)的接口,將參數(shù)設(shè)置替換自己的參數(shù) | 保存起源類對象必需的參數(shù) | 存儲了多條備忘錄辐赞,可以多次撤銷 |
主要優(yōu)點(diǎn):部翘。
- 提供了一種可以恢復(fù)狀態(tài)的機(jī)制。當(dāng)用戶需要時(shí)能夠比較方便地將數(shù)據(jù)恢復(fù)到某個(gè)歷史的狀態(tài)响委。
- 實(shí)現(xiàn)了內(nèi)部狀態(tài)的封裝新思。除了創(chuàng)建它的發(fā)起人之外,其他對象都不能夠訪問這些狀態(tài)信息赘风。
- 簡化了發(fā)起人類夹囚。發(fā)起人不需要管理和保存其內(nèi)部狀態(tài)的各個(gè)備份,所有狀態(tài)信息都保存在備忘錄中邀窃,并由管理者進(jìn)行管理荸哟,這符合單一職責(zé)原則。
主要缺點(diǎn):
資源消耗大瞬捕。如果要保存的內(nèi)部狀態(tài)信息過多或者特別頻繁鞍历,將會(huì)占用比較大的內(nèi)存資源。
實(shí)現(xiàn):
- 發(fā)起人角色:記錄當(dāng)前時(shí)刻的內(nèi)部狀態(tài)信息肪虎,提供創(chuàng)建備忘錄和恢復(fù)備忘錄數(shù)據(jù)的功能劣砍,實(shí)現(xiàn)其他業(yè)務(wù)功能,它可以訪問備忘錄里的所有信息扇救。(Originator)
- 備忘錄角色:負(fù)責(zé)存儲發(fā)起人的內(nèi)部狀態(tài)刑枝,在需要的時(shí)候提供這些內(nèi)部狀態(tài)給發(fā)起人。(Memento)
- 管理者角色:對備忘錄進(jìn)行管理迅腔,提供保存與獲取備忘錄的功能仅讽,但其不能對備忘錄的內(nèi)容進(jìn)行訪問與修改。(Caretaker)
8.狀態(tài)模式(State)
概述:對有狀態(tài)的對象钾挟,把復(fù)雜的“判斷邏輯”提取到不同的狀態(tài)對象中洁灵,允許狀態(tài)對象在其內(nèi)部狀態(tài)發(fā)生改變時(shí)改變其行為。
在軟件開發(fā)過程中掺出,應(yīng)用程序中的有些對象可能會(huì)根據(jù)不同的情況做出不同的行為徽千,我們把這種對象稱為有狀態(tài)的對象汤锨,而把影響對象行為的一個(gè)或多個(gè)動(dòng)態(tài)變化的屬性稱為狀態(tài)。當(dāng)有狀態(tài)的對象與外部事件產(chǎn)生互動(dòng)時(shí)牍汹,其內(nèi)部狀態(tài)會(huì)發(fā)生改變铐维,從而使得其行為也隨之發(fā)生改變。如人的情緒有高興的時(shí)候和傷心的時(shí)候嫁蛇,不同的情緒有不同的行為露该,當(dāng)然外界也會(huì)影響其情緒變化睬棚。
對這種有狀態(tài)的對象編程,傳統(tǒng)的解決方案是:將這些所有可能發(fā)生的情況全都考慮到解幼,然后使用 if-else 語句來做狀態(tài)判斷撵摆,再進(jìn)行不同情況的處理。但當(dāng)對象的狀態(tài)很多時(shí)苛骨,程序會(huì)變得很復(fù)雜苟呐。而且增加新的狀態(tài)要添加新的 if-else 語句牵素,這違背了“開閉原則”笆呆,不利于程序的擴(kuò)展。
主要優(yōu)點(diǎn):
- 狀態(tài)模式將與特定狀態(tài)相關(guān)的行為局部化到一個(gè)狀態(tài)中俄精,并且將不同狀態(tài)的行為分割開來竖慧,滿足“單一職責(zé)原則”逆屡。
- 減少對象間的相互依賴魏蔗。將不同的狀態(tài)引入獨(dú)立的對象中會(huì)使得狀態(tài)轉(zhuǎn)換變得更加明確,且減少對象間的相互依賴廓鞠。
- 有利于程序的擴(kuò)展床佳。通過定義新的子類很容易地增加新的狀態(tài)和轉(zhuǎn)換。
主要缺點(diǎn):
- 狀態(tài)模式的使用必然會(huì)增加系統(tǒng)的類與對象的個(gè)數(shù)馆衔。
- 狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜,如果使用不當(dāng)會(huì)導(dǎo)致程序結(jié)構(gòu)和代碼的混亂篮撑。
實(shí)現(xiàn):
- 環(huán)境角色:也稱為上下文赢笨,它定義了客戶感興趣的接口驮吱,維護(hù)一個(gè)當(dāng)前狀態(tài)左冬,并將與狀態(tài)相關(guān)的操作委托給當(dāng)前狀態(tài)對象來處理拇砰。(Context)
- 抽象狀態(tài)角色:定義一個(gè)接口,用以封裝環(huán)境對象中的特定狀態(tài)所對應(yīng)的行為牧氮。(State)
- 具體狀態(tài)角色:實(shí)現(xiàn)抽象狀態(tài)所對應(yīng)的行為踱葛。(Concrete State)
9.訪問者模式(Visitor)
概述:將用于某穩(wěn)定數(shù)據(jù)結(jié)構(gòu)的不同操作剖毯,提取出來為單獨(dú)的類教馆。使其在不改變數(shù)據(jù)結(jié)構(gòu)代碼的同時(shí)土铺,能夠添加新的行為操作,為其中數(shù)據(jù)節(jié)點(diǎn)能提供多種訪問方式究恤。
它將對數(shù)據(jù)的操作與數(shù)據(jù)結(jié)構(gòu)進(jìn)行分離部宿,是行為類模式中最復(fù)雜的一種模式理张。
例如雾叭,公園中存在多個(gè)景點(diǎn),也存在多個(gè)游客暂幼,不同的游客對同一個(gè)景點(diǎn)的評價(jià)可能不同旺嬉;醫(yī)院醫(yī)生開的處方單中包含多種藥元素邪媳,査看它的劃價(jià)員和藥房工作人員對它的處理方式也不同揽咕,劃價(jià)員根據(jù)處方單上面的藥品名和數(shù)量進(jìn)行劃價(jià)亲善,藥房工作人員根據(jù)處方單的內(nèi)容進(jìn)行抓藥蛹头。
這樣的例子還有很多,例如屠尊,電影或電視劇中的人物角色讼昆,不同的觀眾對他們的評價(jià)也不同浸赫;還有顧客在商場購物時(shí)放在“購物車”中的商品,顧客主要關(guān)心所選商品的性價(jià)比羡榴,而收銀員關(guān)心的是商品的價(jià)格和數(shù)量校仑。
訪問者(Visitor)模式是一種對象行為型模式迄沫。
主要優(yōu)點(diǎn):
- 擴(kuò)展性好邢滑。能夠在不修改對象結(jié)構(gòu)中的元素的情況下愿汰,為對象結(jié)構(gòu)中的元素添加新的功能衬廷。
- 復(fù)用性好吗跋〉穑可以通過訪問者來定義整個(gè)對象結(jié)構(gòu)通用的功能积仗,從而提高系統(tǒng)的復(fù)用程度寂曹。
- 靈活性好隆圆。訪問者模式將數(shù)據(jù)結(jié)構(gòu)與作用于結(jié)構(gòu)上的操作解耦渺氧,使得操作集合可相對自由地演化而不影響系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)。
- 符合單一職責(zé)原則白华。訪問者模式把相關(guān)的行為封裝在一起衬鱼,構(gòu)成一個(gè)訪問者鸟赫,使每一個(gè)訪問者的功能都比較單一抛蚤。
主要缺點(diǎn):
- 增加新的元素類很困難。在訪問者模式中朋沮,每增加一個(gè)新的元素類樊拓,都要在每一個(gè)具體訪問者類中增加相應(yīng)的具體操作筋夏,這違背了“開閉原則”条篷。
- 破壞封裝蛤织。訪問者模式中具體元素對訪問者公布細(xì)節(jié)指蚜,這破壞了對象的封裝性姚炕。
- 違反了依賴倒置原則柱宦。訪問者模式依賴了具體類掸刊,而沒有依賴抽象類。
實(shí)現(xiàn):
- 抽象訪問者角色:定義一個(gè)訪問具體元素的接口牌芋,為每個(gè)具體元素類對應(yīng)一個(gè)訪問操作 visit() 松逊,該操作中的參數(shù)類型標(biāo)識了被訪問的具體元素经宏。(Visitor)
- 具體訪問者角色:實(shí)現(xiàn)抽象訪問者角色中聲明的各個(gè)訪問操作烁兰,確定訪問者訪問一個(gè)元素時(shí)該做什么沪斟。(ConcreteVisitor)
- 抽象元素角色:聲明一個(gè)包含接受操作 accept() 的接口主之,被接受的訪問者對象作為 accept() 方法的參數(shù)杀餐。(Element)
- 具體元素角色:實(shí)現(xiàn)抽象元素角色提供的 accept() 操作史翘,其方法體通常都是 visitor.visit(this) 琼讽,另外具體元素中可能還包含本身業(yè)務(wù)邏輯的相關(guān)操作洪唐。(ConcreteElement)
- 對象結(jié)構(gòu)角色:是一個(gè)包含元素角色的容器凭需,提供讓訪問者對象遍歷容器中的所有元素的方法粒蜈,通常由 List枯怖、Set、Map 等聚合類實(shí)現(xiàn)寿冕。(Object Structure)
10.中介者模式(Mediator)
概述:定義一個(gè)中介類來封裝一些列對象(類)之間的交互驼唱,降低對象間的耦合性曙蒸,且可以獨(dú)立改變他們之間的交互纽窟。中介者模式又叫調(diào)停模式臂港,它是迪米特法則的典型應(yīng)用审孽。中介者模式是一種對象行為型模式佑力,
在現(xiàn)實(shí)生活中打颤,常常會(huì)出現(xiàn)好多對象之間存在復(fù)雜的交互關(guān)系编饺,這種交互關(guān)系常常是“網(wǎng)狀結(jié)構(gòu)”透且,它要求每個(gè)對象都必須知道它需要交互的對象秽誊。例如锅论,每個(gè)人必須記住他(她)所有朋友的電話棍厌;而且,朋友中如果有人的電話修改了敬肚,他(她)必須告訴其他所有的朋友修改艳馒,這叫作“牽一發(fā)而動(dòng)全身”弄慰,非常復(fù)雜。
如果把這種“網(wǎng)狀結(jié)構(gòu)”改為“星形結(jié)構(gòu)”的話扳缕,將大大降低它們之間的“耦合性”躯舔,這時(shí)只要找一個(gè)“中介者”就可以了粥庄。如前面所說的“每個(gè)人必須記住所有朋友電話”的問題惜互,只要在網(wǎng)上建立一個(gè)每個(gè)朋友都可以訪問的“通信錄”就解決了载佳。這樣的例子還有很多,例如姑躲,你剛剛參加工作想租房盟蚣,可以找“房屋中介”阐枣;或者蔼两,自己剛剛到一個(gè)陌生城市找工作额划,可以找“人才交流中心”幫忙俊戳。
在軟件的開發(fā)過程中抑胎,這樣的例子也很多阿逃,例如盆昙,在 MVC 框架中淡喜,控制器(C)就是模型(M)和視圖(V)的中介者炼团;還有大家常用的 QQ 聊天程序的“中介者”是 QQ 服務(wù)器瘟芝。所有這些锌俱,都可以采用“中介者模式”來實(shí)現(xiàn)造寝,它將大大降低對象之間的耦合性诫龙,提高系統(tǒng)的靈活性签赃。
主要優(yōu)點(diǎn):
- 降低了對象之間的耦合性锦聊,使得對象易于獨(dú)立地被復(fù)用括丁。
- 將對象間的一對多關(guān)聯(lián)轉(zhuǎn)變?yōu)橐粚σ坏年P(guān)聯(lián)史飞,提高系統(tǒng)的靈活性构资,使得系統(tǒng)易于維護(hù)和擴(kuò)展迹淌。
主要缺點(diǎn):
當(dāng)同事類太多時(shí)唉窃,中介者的職責(zé)將很大,它會(huì)變得復(fù)雜而龐大纹笼,以至于系統(tǒng)難以維護(hù)
實(shí)現(xiàn):
- 抽象中介者角色:它是中介者的接口纹份,提供了同事對象注冊與轉(zhuǎn)發(fā)同事對象信息的抽象方法。(Mediator)
- 具體中介者角色:實(shí)現(xiàn)中介者接口廷痘,定義一個(gè) List 來管理同事對象蔓涧,協(xié)調(diào)各個(gè)同事角色之間的交互關(guān)系,因此它依賴于同事角色笋额。(ConcreteMediator)
- 抽象同事類角色:定義同事類的接口,保存中介者對象兄猩,提供同事對象交互的抽象方法茉盏,實(shí)現(xiàn)所有相互影響的同事類的公共功能。(Colleague)
- 具體同事類角色:是抽象同事類的實(shí)現(xiàn)者厦滤,當(dāng)需要與其他同事對象交互時(shí)援岩,由中介者對象負(fù)責(zé)后續(xù)的交互。(Concrete Colleague)
11.解釋器模式(Interpreter)
http://c.biancheng.net/view/1402.html
用于面向?qū)ο蟮木幾g解釋器掏导。