創(chuàng)建型模式
工廠模式
工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計模式之一搜锰。這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式耿战。
在工廠模式中蛋叼,我們在創(chuàng)建對象時不會對客戶端暴露創(chuàng)建邏輯,并且是通過使用一個共同的接口來指向新創(chuàng)建的對象剂陡。
介紹
意圖:定義一個創(chuàng)建對象的接口鸦列,讓其子類自己決定實例化哪一個工廠類租冠,工廠模式使其創(chuàng)建過程延遲到子類進行。
主要解決:主要解決接口選擇的問題薯嗤。
何時使用:我們明確地計劃不同條件下創(chuàng)建不同實例時顽爹。
如何解決:讓其子類實現(xiàn)工廠接口,返回的也是一個抽象的產(chǎn)品骆姐。
關(guān)鍵代碼:創(chuàng)建過程在其子類執(zhí)行镜粤。
應(yīng)用實例: 1、您需要一輛汽車玻褪,可以直接從工廠里面提貨肉渴,而不用去管這輛汽車是怎么做出來的,以及這個汽車?yán)锩娴木唧w實現(xiàn)带射。 2同规、Hibernate 換數(shù)據(jù)庫只需換方言和驅(qū)動就可以。
優(yōu)點: 1窟社、一個調(diào)用者想創(chuàng)建一個對象券勺,只要知道其名稱就可以了。 2灿里、擴展性高关炼,如果想增加一個產(chǎn)品,只要擴展一個工廠類就可以匣吊。 3儒拂、屏蔽產(chǎn)品的具體實現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口色鸳。
缺點:每次增加一個產(chǎn)品時社痛,都需要增加一個具體類和對象實現(xiàn)工廠,使得系統(tǒng)中類的個數(shù)成倍增加命雀,在一定程度上增加了系統(tǒng)的復(fù)雜度蒜哀,同時也增加了系統(tǒng)具體類的依賴。這并不是什么好事咏雌。
使用場景: 1、日志記錄器:記錄可能記錄到本地硬盤校焦、系統(tǒng)事件赊抖、遠程服務(wù)器等,用戶可以選擇記錄日志到什么地方寨典。 2氛雪、數(shù)據(jù)庫訪問,當(dāng)用戶不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫耸成,以及數(shù)據(jù)庫可能有變化時报亩。 3浴鸿、設(shè)計一個連接服務(wù)器的框架,需要三個協(xié)議弦追,"POP3"岳链、"IMAP"、"HTTP"劲件,可以把這三個作為產(chǎn)品類掸哑,共同實現(xiàn)一個接口。
注意事項:作為一種創(chuàng)建類模式零远,在任何需要生成復(fù)雜對象的地方苗分,都可以使用工廠方法模式。有一點需要注意的地方就是復(fù)雜對象適合使用工廠模式牵辣,而簡單對象摔癣,特別是只需要通過 new 就可以完成創(chuàng)建的對象,無需使用工廠模式纬向。如果使用工廠模式择浊,就需要引入一個工廠類,會增加系統(tǒng)的復(fù)雜度罢猪。
抽象工廠模式
抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠創(chuàng)建其他工廠近她。該超級工廠又稱為其他工廠的工廠。這種類型的設(shè)計模式屬于創(chuàng)建型模式膳帕,它提供了一種創(chuàng)建對象的最佳方式粘捎。
在抽象工廠模式中,接口是負(fù)責(zé)創(chuàng)建一個相關(guān)對象的工廠危彩,不需要顯式指定它們的類攒磨。每個生成的工廠都能按照工廠模式提供對象。
介紹
意圖:提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口汤徽,而無需指定它們具體的類娩缰。
主要解決:主要解決接口選擇的問題。
何時使用:系統(tǒng)的產(chǎn)品有多于一個的產(chǎn)品族谒府,而系統(tǒng)只消費其中某一族的產(chǎn)品拼坎。
如何解決:在一個產(chǎn)品族里面,定義多個產(chǎn)品完疫。
關(guān)鍵代碼:在一個工廠里聚合多個同類產(chǎn)品泰鸡。
應(yīng)用實例:工作了,為了參加一些聚會壳鹤,肯定有兩套或多套衣服吧盛龄,比如說有商務(wù)裝(成套,一系列具體產(chǎn)品)、時尚裝(成套余舶,一系列具體產(chǎn)品)啊鸭,甚至對于一個家庭來說,可能有商務(wù)女裝匿值、商務(wù)男裝赠制、時尚女裝、時尚男裝千扔,這些也都是成套的憎妙,即一系列具體產(chǎn)品。假設(shè)一種情況(現(xiàn)實中是不存在的曲楚,要不然厘唾,沒法進入共產(chǎn)主義了,但有利于說明抽象工廠模式)龙誊,在您的家中抚垃,某一個衣柜(具體工廠)只能存放某一種這樣的衣服(成套,一系列具體產(chǎn)品)趟大,每次拿這種成套的衣服時也自然要從這個衣柜中取出了鹤树。用 OO 的思想去理解,所有的衣柜(具體工廠)都是衣柜類的(抽象工廠)某一個逊朽,而每一件成套的衣服又包括具體的上衣(某一具體產(chǎn)品)罕伯,褲子(某一具體產(chǎn)品),這些具體的上衣其實也都是上衣(抽象產(chǎn)品)叽讳,具體的褲子也都是褲子(另一個抽象產(chǎn)品)追他。
優(yōu)點:當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象岛蚤。
缺點:產(chǎn)品族擴展非常困難邑狸,要增加一個系列的某一產(chǎn)品,既要在抽象的 Creator 里加代碼涤妒,又要在具體的里面加代碼单雾。
使用場景: 1、QQ 換皮膚她紫,一整套一起換硅堆。 2、生成不同操作系統(tǒng)的程序贿讹。
注意事項:產(chǎn)品族難擴展渐逃,產(chǎn)品等級易擴展。
單例模式
單例模式(Singleton Pattern)是 Java 中最簡單的設(shè)計模式之一围详。這種類型的設(shè)計模式屬于創(chuàng)建型模式朴乖,它提供了一種創(chuàng)建對象的最佳方式。
這種模式涉及到一個單一的類助赞,該類負(fù)責(zé)創(chuàng)建自己的對象买羞,同時確保只有單個對象被創(chuàng)建。這個類提供了一種訪問其唯一的對象的方式雹食,可以直接訪問畜普,不需要實例化該類的對象。
注意:
1群叶、單例類只能有一個實例吃挑。
2、單例類必須自己創(chuàng)建自己的唯一實例街立。
3舶衬、單例類必須給所有其他對象提供這一實例。
介紹
意圖:保證一個類僅有一個實例赎离,并提供一個訪問它的全局訪問點逛犹。
主要解決:一個全局使用的類頻繁地創(chuàng)建與銷毀。
何時使用:當(dāng)您想控制實例數(shù)目梁剔,節(jié)省系統(tǒng)資源的時候虽画。
如何解決:判斷系統(tǒng)是否已經(jīng)有這個單例,如果有則返回荣病,如果沒有則創(chuàng)建码撰。
關(guān)鍵代碼:構(gòu)造函數(shù)是私有的。
應(yīng)用實例: 1个盆、一個黨只能有一個主席脖岛。 2、Windows 是多進程多線程的砾省,在操作一個文件的時候鸡岗,就不可避免地出現(xiàn)多個進程或線程同時操作一個文件的現(xiàn)象,所以所有文件的處理必須通過唯一的實例來進行编兄。 3轩性、一些設(shè)備管理器常常設(shè)計為單例模式,比如一個電腦有兩臺打印機狠鸳,在輸出的時候就要處理不能兩臺打印機打印同一個文件揣苏。
優(yōu)點: 1、在內(nèi)存里只有一個實例件舵,減少了內(nèi)存的開銷卸察,尤其是頻繁的創(chuàng)建和銷毀實例(比如管理學(xué)院首頁頁面緩存)。 2铅祸、避免對資源的多重占用(比如寫文件操作)坑质。
缺點:沒有接口合武,不能繼承,與單一職責(zé)原則沖突涡扼,一個類應(yīng)該只關(guān)心內(nèi)部邏輯稼跳,而不關(guān)心外面怎么樣來實例化。
使用場景: 1吃沪、要求生產(chǎn)唯一序列號汤善。 2、WEB 中的計數(shù)器票彪,不用每次刷新都在數(shù)據(jù)庫里加一次红淡,用單例先緩存起來。 3降铸、創(chuàng)建的一個對象需要消耗的資源過多在旱,比如 I/O 與數(shù)據(jù)庫的連接等。
注意事項:getInstance() 方法中需要使用同步鎖 synchronized (Singleton.class) 防止多線程同時進入造成 instance 被多次實例化推掸。
建造者模式(構(gòu)建者模式)
建造者模式(Builder Pattern)使用多個簡單的對象一步一步構(gòu)建成一個復(fù)雜的對象颈渊。這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式终佛。
一個 Builder 類會一步一步構(gòu)造最終的對象俊嗽。該 Builder 類是獨立于其他對象的。
介紹
意圖:將一個復(fù)雜的構(gòu)建與其表示相分離铃彰,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示绍豁。
主要解決:主要解決在軟件系統(tǒng)中,有時候面臨著"一個復(fù)雜對象"的創(chuàng)建工作牙捉,其通常由各個部分的子對象用一定的算法構(gòu)成竹揍;由于需求的變化,這個復(fù)雜對象的各個部分經(jīng)常面臨著劇烈的變化邪铲,但是將它們組合在一起的算法卻相對穩(wěn)定芬位。
何時使用:一些基本部件不會變,而其組合經(jīng)常變化的時候带到。
如何解決:將變與不變分離開昧碉。
關(guān)鍵代碼:建造者:創(chuàng)建和提供實例,導(dǎo)演:管理建造出來的實例的依賴關(guān)系揽惹。
應(yīng)用實例: 1被饿、去肯德基,漢堡搪搏、可樂狭握、薯條、炸雞翅等是不變的疯溺,而其組合是經(jīng)常變化的论颅,生成出所謂的"套餐"哎垦。 2、JAVA 中的 StringBuilder恃疯。
優(yōu)點: 1撼泛、建造者獨立,易擴展澡谭。 2、便于控制細節(jié)風(fēng)險损俭。
缺點: 1蛙奖、產(chǎn)品必須有共同點,范圍有限制杆兵。 2雁仲、如內(nèi)部變化復(fù)雜,會有很多的建造類琐脏。
使用場景: 1攒砖、需要生成的對象具有復(fù)雜的內(nèi)部結(jié)構(gòu)。 2日裙、需要生成的對象內(nèi)部屬性本身相互依賴。
注意事項:與工廠模式的區(qū)別是:建造者模式更加關(guān)注與零件裝配的順序。
原型模式
原型模式(Prototype Pattern)是用于創(chuàng)建重復(fù)的對象仅颇,同時又能保證性能剖膳。這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式格侯。
這種模式是實現(xiàn)了一個原型接口鼻听,該接口用于創(chuàng)建當(dāng)前對象的克隆。當(dāng)直接創(chuàng)建對象的代價比較大時联四,則采用這種模式撑碴。例如,一個對象需要在一個高代價的數(shù)據(jù)庫操作之后被創(chuàng)建朝墩。我們可以緩存該對象醉拓,在下一個請求時返回它的克隆,在需要的時候更新數(shù)據(jù)庫收苏,以此來減少數(shù)據(jù)庫調(diào)用廉嚼。
介紹
意圖:用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象倒戏。
主要解決:在運行期建立和刪除原型怠噪。
何時使用: 1、當(dāng)一個系統(tǒng)應(yīng)該獨立于它的產(chǎn)品創(chuàng)建杜跷,構(gòu)成和表示時傍念。 2矫夷、當(dāng)要實例化的類是在運行時刻指定時,例如憋槐,通過動態(tài)裝載双藕。 3、為了避免創(chuàng)建一個與產(chǎn)品類層次平行的工廠類層次時阳仔。 4忧陪、當(dāng)一個類的實例只能有幾個不同狀態(tài)組合中的一種時。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實例化該類更方便一些近范。
如何解決:利用已有的一個原型對象嘶摊,快速地生成和原型對象一樣的實例。
關(guān)鍵代碼: 1评矩、實現(xiàn)克隆操作叶堆,在 JAVA 繼承 Cloneable,重寫 clone()斥杜,在 .NET 中可以使用 Object 類的 MemberwiseClone() 方法來實現(xiàn)對象的淺拷貝或通過序列化的方式來實現(xiàn)深拷貝虱颗。 2、原型模式同樣用于隔離類對象的使用者和具體類型(易變類)之間的耦合關(guān)系蔗喂,它同樣要求這些"易變類"擁有穩(wěn)定的接口忘渔。
應(yīng)用實例: 1、細胞分裂缰儿。 2辨萍、JAVA 中的 Object clone() 方法。
優(yōu)點: 1返弹、性能提高锈玉。 2、逃避構(gòu)造函數(shù)的約束义起。
缺點: 1拉背、配備克隆方法需要對類的功能進行通盤考慮,這對于全新的類不是很難默终,但對于已有的類不一定很容易椅棺,特別當(dāng)一個類引用不支持串行化的間接對象,或者引用含有循環(huán)結(jié)構(gòu)的時候齐蔽。 2两疚、必須實現(xiàn) Cloneable 接口。
使用場景:
資源優(yōu)化場景含滴。
類初始化需要消化非常多的資源诱渤,這個資源包括數(shù)據(jù)、硬件資源等谈况。?
性能和安全要求的場景勺美。?
通過 new 產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限递胧,則可以使用原型模式。?
一個對象多個修改者的場景赡茸。?
一個對象需要提供給其他對象訪問缎脾,而且各個調(diào)用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調(diào)用者使用占卧。?
在實際項目中遗菠,原型模式很少單獨出現(xiàn),一般是和工廠方法模式一起出現(xiàn)华蜒,通過 clone 的方法創(chuàng)建一個對象辙纬,然后由工廠方法提供給調(diào)用者。原型模式已經(jīng)與 Java 融為渾然一體友多,大家可以隨手拿來使用。
注意事項:與通過對一個類進行實例化來構(gòu)造新對象不同的是堤框,原型模式是通過拷貝一個現(xiàn)有對象生成新對象的域滥。淺拷貝實現(xiàn) Cloneable,重寫蜈抓,深拷貝是通過實現(xiàn) Serializable 讀取二進制流启绰。
結(jié)構(gòu)型模式
適配器模式
適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式沟使,它結(jié)合了兩個獨立接口的功能委可。
這種模式涉及到一個單一的類,該類負(fù)責(zé)加入獨立的或不兼容的接口功能腊嗡。舉個真實的例子着倾,讀卡器是作為內(nèi)存卡和筆記本之間的適配器。您將內(nèi)存卡插入讀卡器燕少,再將讀卡器插入筆記本卡者,這樣就可以通過筆記本來讀取內(nèi)存卡。
我們通過下面的實例來演示適配器模式的使用客们。其中崇决,音頻播放器設(shè)備只能播放 mp3 文件,通過使用一個更高級的音頻播放器來播放 vlc 和 mp4 文件底挫。
介紹
意圖:將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口恒傻。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
主要解決:主要解決在軟件系統(tǒng)中建邓,常常要將一些"現(xiàn)存的對象"放到新的環(huán)境中盈厘,而新環(huán)境要求的接口是現(xiàn)對象不能滿足的。
何時使用: 1官边、系統(tǒng)需要使用現(xiàn)有的類扑庞,而此類的接口不符合系統(tǒng)的需要譬重。 2、想要建立一個可以重復(fù)使用的類罐氨,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類臀规,包括一些可能在將來引進的類一起工作,這些源類不一定有一致的接口栅隐。 3塔嬉、通過接口轉(zhuǎn)換,將一個類插入另一個類系中租悄。(比如老虎和飛禽谨究,現(xiàn)在多了一個飛虎,在不增加實體的需求下泣棋,增加一個適配器胶哲,在里面包容一個虎對象,實現(xiàn)飛的接口潭辈。)
如何解決:繼承或依賴(推薦)鸯屿。
關(guān)鍵代碼:適配器繼承或依賴已有的對象,實現(xiàn)想要的目標(biāo)接口把敢。
應(yīng)用實例: 1寄摆、美國電器 110V,中國 220V修赞,就要有一個適配器將 110V 轉(zhuǎn)化為 220V婶恼。 2、JAVA JDK 1.1 提供了 Enumeration 接口柏副,而在 1.2 中提供了 Iterator 接口勾邦,想要使用 1.2 的 JDK,則要將以前系統(tǒng)的 Enumeration 接口轉(zhuǎn)化為 Iterator 接口割择,這時就需要適配器模式检痰。 3、在 LINUX 上運行 WINDOWS 程序锨推。 4铅歼、JAVA 中的 jdbc。
優(yōu)點: 1换可、可以讓任何兩個沒有關(guān)聯(lián)的類一起運行椎椰。 2、提高了類的復(fù)用沾鳄。 3慨飘、增加了類的透明度。 4、靈活性好瓤的。
缺點: 1休弃、過多地使用適配器,會讓系統(tǒng)非常零亂圈膏,不易整體進行把握塔猾。比如,明明看到調(diào)用的是 A 接口稽坤,其實內(nèi)部被適配成了 B 接口的實現(xiàn)丈甸,一個系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場災(zāi)難尿褪。因此如果不是很有必要睦擂,可以不使用適配器,而是直接對系統(tǒng)進行重構(gòu)杖玲。 2.由于 JAVA 至多繼承一個類顿仇,所以至多只能適配一個適配者類,而且目標(biāo)類必須是抽象類摆马。
使用場景:有動機地修改一個正常運行的系統(tǒng)的接口臼闻,這時應(yīng)該考慮使用適配器模式。
注意事項:適配器不是在詳細設(shè)計時添加的今膊,而是解決正在服役的項目的問題些阅。
裝飾器模式
裝飾器模式(Decorator Pattern)允許向一個現(xiàn)有的對象添加新的功能伞剑,同時又不改變其結(jié)構(gòu)斑唬。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個包裝黎泣。
這種模式創(chuàng)建了一個裝飾類恕刘,用來包裝原有的類,并在保持類方法簽名完整性的前提下抒倚,提供了額外的功能褐着。
我們通過下面的實例來演示裝飾器模式的用法。其中托呕,我們將把一個形狀裝飾上不同的顏色含蓉,同時又不改變形狀類。
介紹
意圖:動態(tài)地給一個對象添加一些額外的職責(zé)项郊。就增加功能來說馅扣,裝飾器模式相比生成子類更為靈活。
主要解決:一般的着降,我們?yōu)榱藬U展一個類經(jīng)常使用繼承方式實現(xiàn)差油,由于繼承為類引入靜態(tài)特征,并且隨著擴展功能的增多,子類會很膨脹蓄喇。
何時使用:在不想增加很多子類的情況下擴展類发侵。
如何解決:將具體功能職責(zé)劃分,同時繼承裝飾者模式妆偏。
關(guān)鍵代碼: 1刃鳄、Component 類充當(dāng)抽象角色,不應(yīng)該具體實現(xiàn)楼眷。 2铲汪、修飾類引用和繼承 Component 類,具體擴展類重寫父類方法罐柳。
應(yīng)用實例: 1掌腰、孫悟空有 72 變,當(dāng)他變成"廟宇"后张吉,他的根本還是一只猴子齿梁,但是他又有了廟宇的功能。 2肮蛹、不論一幅畫有沒有畫框都可以掛在墻上勺择,但是通常都是有畫框的,并且實際上是畫框被掛在墻上伦忠。在掛在墻上之前省核,畫可以被蒙上玻璃,裝到框子里昆码;這時畫气忠、玻璃和畫框形成了一個物體。
優(yōu)點:裝飾類和被裝飾類可以獨立發(fā)展赋咽,不會相互耦合旧噪,裝飾模式是繼承的一個替代模式,裝飾模式可以動態(tài)擴展一個實現(xiàn)類的功能脓匿。
缺點:多層裝飾比較復(fù)雜淘钟。
使用場景: 1、擴展一個類的功能陪毡。 2米母、動態(tài)增加功能,動態(tài)撤銷毡琉。
注意事項:可代替繼承铁瞒。
代理模式
在代理模式(Proxy Pattern)中,一個類代表另一個類的功能绊起。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式精拟。
在代理模式中,我們創(chuàng)建具有現(xiàn)有對象的對象,以便向外界提供功能接口蜂绎。
介紹
意圖:為其他對象提供一種代理以控制對這個對象的訪問栅表。
主要解決:在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上师枣。在面向?qū)ο笙到y(tǒng)中怪瓶,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制践美,或者需要進程外的訪問)洗贰,直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層陨倡。
何時使用:想在訪問一個類時做一些控制敛滋。
如何解決:增加中間層。
關(guān)鍵代碼:實現(xiàn)與被代理類組合兴革。
應(yīng)用實例:
Windows 里面的快捷方式绎晃。
豬八戒去找高翠蘭結(jié)果是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來杂曲,高翠蘭本人和孫悟空都實現(xiàn)了這個接口庶艾,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,所以說孫悟空是高翠蘭代理類擎勘。
買火車票不一定在火車站買咱揍,也可以去代售點。
一張支票或銀行存單是賬戶中資金的代理棚饵。支票在市場交易中用來代替現(xiàn)金煤裙,并提供對簽發(fā)人賬號上資金的控制。
spring aop蟹地。
優(yōu)點: 1积暖、職責(zé)清晰藤为。 2怪与、高擴展性。 3缅疟、智能化分别。
缺點:
由于在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢存淫。
實現(xiàn)代理模式需要額外的工作耘斩,有些代理模式的實現(xiàn)非常復(fù)雜。
使用場景:按職責(zé)來劃分桅咆,通常有以下使用場景: 1括授、遠程代理。 2、虛擬代理荚虚。 3薛夜、Copy-on-Write 代理。 4版述、保護(Protect or Access)代理梯澜。 5、Cache代理渴析。 6晚伙、防火墻(Firewall)代理。 7俭茧、同步化(Synchronization)代理咆疗。 8、智能引用(Smart Reference)代理母债。
注意事項:
和適配器模式的區(qū)別:適配器模式主要改變所考慮對象的接口民傻,而代理模式不能改變所代理類的接口。?
和裝飾器模式的區(qū)別:裝飾器模式為了增強功能场斑,而代理模式是為了加以控制漓踢。
外觀模式
外觀模式(Facade Pattern)隱藏系統(tǒng)的復(fù)雜性,并向客戶端提供了一個客戶端可以訪問系統(tǒng)的接口漏隐。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式喧半,它向現(xiàn)有的系統(tǒng)添加一個接口,來隱藏系統(tǒng)的復(fù)雜性青责。
這種模式涉及到一個單一的類挺据,該類提供了客戶端請求的簡化方法和對現(xiàn)有系統(tǒng)類方法的委托調(diào)用。
介紹
意圖:為子系統(tǒng)中的一組接口提供一個一致的界面脖隶,外觀模式定義了一個高層接口扁耐,這個接口使得這一子系統(tǒng)更加容易使用。
主要解決:降低訪問復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)時的復(fù)雜度产阱,簡化客戶端與之的接口婉称。
何時使用:
客戶端不需要知道系統(tǒng)內(nèi)部的復(fù)雜聯(lián)系,整個系統(tǒng)只需提供一個"接待員"即可构蹬。?
定義系統(tǒng)的入口王暗。
如何解決:客戶端不與系統(tǒng)耦合,外觀類與系統(tǒng)耦合庄敛。
關(guān)鍵代碼:在客戶端和復(fù)雜系統(tǒng)之間再加一層俗壹,這一層將調(diào)用順序、依賴關(guān)系等處理好藻烤。
應(yīng)用實例:
去醫(yī)院看病绷雏,可能要去掛號头滔、門診、劃價涎显、取藥拙毫,讓患者或患者家屬覺得很復(fù)雜,如果有提供接待人員棺禾,只讓接待人員來處理缀蹄,就很方便。
JAVA 的三層開發(fā)模式膘婶。
優(yōu)點: 1缺前、減少系統(tǒng)相互依賴。 2悬襟、提高靈活性衅码。 3、提高了安全性脊岳。
缺點:不符合開閉原則逝段,如果要改東西很麻煩,繼承重寫都不合適割捅。
使用場景:
為復(fù)雜的模塊或子系統(tǒng)提供外界訪問的模塊奶躯。?
子系統(tǒng)相對獨立。
預(yù)防低水平人員帶來的風(fēng)險亿驾。
注意事項:在層次化結(jié)構(gòu)中嘹黔,可以使用外觀模式定義系統(tǒng)中每一層的入口。
橋接模式
橋接(Bridge)是用于把抽象化與實現(xiàn)化解耦莫瞬,使得二者可以獨立變化儡蔓。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它通過提供抽象化和實現(xiàn)化之間的橋接結(jié)構(gòu)疼邀,來實現(xiàn)二者的解耦喂江。
這種模式涉及到一個作為橋接的接口,使得實體類的功能獨立于接口實現(xiàn)類旁振。這兩種類型的類可被結(jié)構(gòu)化改變而互不影響获询。
我們通過下面的實例來演示橋接模式(Bridge Pattern)的用法。其中规求,可以使用相同的抽象類方法但是不同的橋接實現(xiàn)類筐付,來畫出不同顏色的圓卵惦。
介紹
意圖:將抽象部分與實現(xiàn)部分分離阻肿,使它們都可以獨立的變化。
主要解決:在有多種可能會變化的情況下沮尿,用繼承會造成類爆炸問題丛塌,擴展起來不靈活较解。
何時使用:實現(xiàn)系統(tǒng)可能有多個角度分類,每一種角度都可能變化赴邻。
如何解決:把這種多角度分類分離出來印衔,讓它們獨立變化,減少它們之間耦合姥敛。
關(guān)鍵代碼:抽象類依賴實現(xiàn)類奸焙。
應(yīng)用實例:
豬八戒從天蓬元帥轉(zhuǎn)世投胎到豬,轉(zhuǎn)世投胎的機制將塵世劃分為兩個等級彤敛,即:靈魂和肉體与帆,前者相當(dāng)于抽象化闺属,后者相當(dāng)于實現(xiàn)化炬藤。生靈通過功能的委派武翎,調(diào)用肉體對象的功能枷畏,使得生靈可以動態(tài)地選擇禁漓。
墻上的開關(guān)之剧,可以看到的開關(guān)是抽象的郭卫,不用管里面具體怎么實現(xiàn)的背稼。
優(yōu)點: 1、抽象和實現(xiàn)的分離雇庙。 2谓形、優(yōu)秀的擴展能力寒跳。 3竹椒、實現(xiàn)細節(jié)對客戶透明胸完。
缺點:橋接模式的引入會增加系統(tǒng)的理解與設(shè)計難度赊窥,由于聚合關(guān)聯(lián)關(guān)系建立在抽象層锨能,要求開發(fā)者針對抽象進行設(shè)計與編程。
使用場景:
如果一個系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性斋竞,避免在兩個層次之間建立靜態(tài)的繼承聯(lián)系坝初,通過橋接模式可以使它們在抽象層建立一個關(guān)聯(lián)關(guān)系脖卖。?
對于那些不希望使用繼承或因為多層次繼承導(dǎo)致系統(tǒng)類的個數(shù)急劇增加的系統(tǒng)畦木,橋接模式尤為適用十籍。?
一個類存在兩個獨立變化的維度唇礁,且這兩個維度都需要進行擴展盏筐。
注意事項:對于兩個獨立變化的維度琢融,使用橋接模式再適合不過了漾抬。
組合模式
組合模式(Composite Pattern)纳令,又叫部分整體模式平绩,是用于把一組相似的對象當(dāng)作一個單一的對象捏雌。組合模式依據(jù)樹形結(jié)構(gòu)來組合對象腹忽,用來表示部分以及整體層次窘奏。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式着裹,它創(chuàng)建了對象組的樹形結(jié)構(gòu)骇扇。
這種模式創(chuàng)建了一個包含自己對象組的類少孝。該類提供了修改相同對象組的方式稍走。
我們通過下面的實例來演示組合模式的用法婿脸。實例演示了一個組織中員工的層次結(jié)構(gòu)狐树。
介紹
意圖:將對象組合成樹形結(jié)構(gòu)以表示"部分-整體"的層次結(jié)構(gòu)抑钟。組合模式使得用戶對單個對象和組合對象的使用具有一致性在塔。
主要解決:它在我們樹型結(jié)構(gòu)的問題中心俗,模糊了簡單元素和復(fù)雜元素的概念城榛,客戶程序可以向處理簡單元素一樣來處理復(fù)雜元素疟位,從而使得客戶程序與復(fù)雜元素的內(nèi)部結(jié)構(gòu)解耦甜刻。
何時使用:
您想表示對象的部分-整體層次結(jié)構(gòu)(樹形結(jié)構(gòu))得院。?
您希望用戶忽略組合對象與單個對象的不同祥绞,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對象蜕径。
如何解決:樹枝和葉子實現(xiàn)統(tǒng)一接口兜喻,樹枝內(nèi)部組合該接口朴皆。
關(guān)鍵代碼:樹枝內(nèi)部組合該接口车荔,并且含有內(nèi)部屬性 List族吻,里面放 Component超歌。
應(yīng)用實例:
算術(shù)表達式包括操作數(shù)巍举、操作符和另一個操作數(shù)懊悯,其中炭分,另一個操作符也可以是操作數(shù)捧毛、操作符和另一個操作數(shù)师痕。?
在 JAVA AWT 和 SWING 中胰坟,對于 Button 和 Checkbox 是樹葉腕铸,Container 是樹枝。
優(yōu)點: 1汽烦、高層模塊調(diào)用簡單撇吞。 2牍颈、節(jié)點自由增加涣易。
缺點:在使用組合模式時步氏,其葉子和樹枝的聲明都是實現(xiàn)類,而不是接口界阁,違反了依賴倒置原則铺董。
使用場景:部分坝锰、整體場景,如樹形菜單,文件、文件夾的管理。
注意事項:定義時為具體類。
享元模式
享元模式(Flyweight Pattern)主要用于減少創(chuàng)建對象的數(shù)量,以減少內(nèi)存占用和提高性能。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它提供了減少對象數(shù)量從而改善應(yīng)用所需的對象結(jié)構(gòu)的方式。
享元模式嘗試重用現(xiàn)有的同類對象,如果未找到匹配的對象,則創(chuàng)建新對象栅螟。我們將通過創(chuàng)建 5 個對象來畫出 20 個分布于不同位置的圓來演示這種模式掺逼。由于只有 5 種可用的顏色,所以 color 屬性被用來檢查現(xiàn)有的 Circle 對象。
介紹
意圖:運用共享技術(shù)有效地支持大量細粒度的對象梁肿。
主要解決:在有大量對象時,有可能會造成內(nèi)存溢出隧期,我們把其中共同的部分抽象出來仆潮,如果有相同的業(yè)務(wù)請求,直接返回在內(nèi)存中已有的對象鹏浅,避免重新創(chuàng)建隐砸。
何時使用: 1、系統(tǒng)中有大量對象式塌。 2珊搀、這些對象消耗大量內(nèi)存囚枪。 3链沼、這些對象的狀態(tài)大部分可以外部化。 4疾捍、這些對象可以按照內(nèi)蘊狀態(tài)分為很多組乱豆,當(dāng)把外蘊對象從對象中剔除出來時,每一組對象都可以用一個對象來代替揩尸。 5、系統(tǒng)不依賴于這些對象身份朗恳,這些對象是不可分辨的。
如何解決:用唯一標(biāo)識碼判斷怀浆,如果在內(nèi)存中有镰踏,則返回這個唯一標(biāo)識碼所標(biāo)識的對象奠伪。
關(guān)鍵代碼:用 HashMap 存儲這些對象。
應(yīng)用實例: 1滤否、JAVA 中的 String,如果有則返回欲芹,如果沒有則創(chuàng)建一個字符串保存在字符串緩存池里面耀石。 2揭鳞、數(shù)據(jù)庫的數(shù)據(jù)池称开。
優(yōu)點:大大減少對象的創(chuàng)建鳖轰,降低系統(tǒng)的內(nèi)存,使效率提高昆雀。
缺點:提高了系統(tǒng)的復(fù)雜度狞膘,需要分離出外部狀態(tài)和內(nèi)部狀態(tài)已球,而且外部狀態(tài)具有固有化的性質(zhì),不應(yīng)該隨著內(nèi)部狀態(tài)的變化而變化鸽素,否則會造成系統(tǒng)的混亂。
使用場景: 1燕差、系統(tǒng)有大量相似對象遭笋。 2、需要緩沖池的場景徒探。
注意事項: 1瓦呼、注意劃分外部狀態(tài)和內(nèi)部狀態(tài),否則可能會引起線程安全問題测暗。 2、這些類必須有一個工廠對象加以控制碗啄。
行為型模式
策略模式
在策略模式(Strategy Pattern)中质和,一個類的行為或其算法可以在運行時更改。這種類型的設(shè)計模式屬于行為型模式稚字。
在策略模式中饲宿,我們創(chuàng)建表示各種策略的對象和一個行為隨著策略對象改變而改變的 context 對象。策略對象改變 context 對象的執(zhí)行算法胆描。
介紹
意圖:定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換瘫想。
主要解決:在有多種算法相似的情況下,使用 if...else 所帶來的復(fù)雜和難以維護昌讲。
何時使用:一個系統(tǒng)有許多許多類国夜,而區(qū)分它們的只是他們直接的行為。
如何解決:將這些算法封裝成一個一個的類剧蚣,任意地替換支竹。
關(guān)鍵代碼:實現(xiàn)同一個接口旋廷。
應(yīng)用實例: 1、諸葛亮的錦囊妙計礼搁,每一個錦囊就是一個策略饶碘。 2、旅行的出游方式馒吴,選擇騎自行車扎运、坐汽車,每一種旅行方式都是一個策略饮戳。 3豪治、JAVA AWT 中的 LayoutManager。
優(yōu)點: 1扯罐、算法可以自由切換负拟。 2、避免使用多重條件判斷歹河。 3掩浙、擴展性良好。
缺點: 1秸歧、策略類會增多厨姚。 2、所有策略類都需要對外暴露键菱。
使用場景: 1谬墙、如果在一個系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為经备,那么使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為拭抬。 2、一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種弄喘。 3玖喘、如果一個對象有很多的行為,如果不用恰當(dāng)?shù)哪J侥⒅荆@些行為就只好使用多重的條件選擇語句來實現(xiàn)。
注意事項:如果一個系統(tǒng)的策略多于四個贬派,就需要考慮使用混合模式急但,解決策略類膨脹的問題。
模板模式
在模板模式(Template Pattern)中搞乏,一個抽象類公開定義了執(zhí)行它的方法的方式/模板波桩。它的子類可以按需要重寫方法實現(xiàn),但調(diào)用將以抽象類中定義的方式進行请敦。這種類型的設(shè)計模式屬于行為型模式镐躲。
介紹
意圖:定義一個操作中的算法的骨架储玫,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟萤皂。
主要解決:一些方法通用撒穷,卻在每一個子類都重新寫了這一方法。
何時使用:有一些通用的方法裆熙。
如何解決:將這些通用算法抽象出來端礼。
關(guān)鍵代碼:在抽象類實現(xiàn),其他步驟在子類實現(xiàn)入录。
應(yīng)用實例:
在造房子的時候蛤奥,地基、走線僚稿、水管都一樣凡桥,只有在建筑的后期才有加壁櫥加?xùn)艡诘炔町悺?
西游記里面菩薩定好的 81 難,這就是一個頂層的邏輯骨架蚀同。?
spring 中對 Hibernate 的支持缅刽,將一些已經(jīng)定好的方法封裝起來,比如開啟事務(wù)唤崭、獲取 Session拷恨、關(guān)閉 Session 等,程序員不重復(fù)寫那些已經(jīng)規(guī)范好的代碼谢肾,直接丟一個實體就可以保存腕侄。
優(yōu)點: 1、封裝不變部分芦疏,擴展可變部分冕杠。 2、提取公共代碼酸茴,便于維護分预。 3、行為由父類控制薪捍,子類實現(xiàn)笼痹。
缺點:每一個不同的實現(xiàn)都需要一個子類來實現(xiàn),導(dǎo)致類的個數(shù)增加酪穿,使得系統(tǒng)更加龐大凳干。
使用場景: 1、有多個子類共有的方法被济,且邏輯相同救赐。 2、重要的只磷、復(fù)雜的方法经磅,可以考慮作為模板方法泌绣。
注意事項:為防止惡意操作,一般模板方法都加上 final 關(guān)鍵詞预厌。
觀察者模式
當(dāng)對象間存在一對多關(guān)系時阿迈,則使用觀察者模式(Observer Pattern)。比如配乓,當(dāng)一個對象被修改時仿滔,則會自動通知它的依賴對象。觀察者模式屬于行為型模式犹芹。
介紹
意圖:定義對象間的一種一對多的依賴關(guān)系崎页,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新腰埂。
主要解決:一個對象狀態(tài)改變給其他對象通知的問題飒焦,而且要考慮到易用和低耦合,保證高度的協(xié)作屿笼。
何時使用:一個對象(目標(biāo)對象)的狀態(tài)發(fā)生改變牺荠,所有的依賴對象(觀察者對象)都將得到通知,進行廣播通知驴一。
如何解決:使用面向?qū)ο蠹夹g(shù)休雌,可以將這種依賴關(guān)系弱化。
關(guān)鍵代碼:在抽象類里有一個 ArrayList 存放觀察者們肝断。
應(yīng)用實例:
拍賣的時候杈曲,拍賣師觀察最高標(biāo)價,然后通知給其他競價者競價胸懈。
西游記里面悟空請求菩薩降服紅孩兒担扑,菩薩灑了一地水招來一個老烏龜,這個烏龜就是觀察者趣钱,他觀察菩薩灑水這個動作涌献。
優(yōu)點: 1、觀察者和被觀察者是抽象耦合的首有。 2燕垃、建立一套觸發(fā)機制。
缺點:
如果一個被觀察者對象有很多的直接和間接的觀察者的話井联,將所有的觀察者都通知到會花費很多時間利术。?
如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會觸發(fā)它們之間進行循環(huán)調(diào)用低矮,可能導(dǎo)致系統(tǒng)崩潰。?
觀察者模式?jīng)]有相應(yīng)的機制讓觀察者知道所觀察的目標(biāo)對象是怎么發(fā)生變化的被冒,而僅僅只是知道觀察目標(biāo)發(fā)生了變化军掂。
使用場景:
一個抽象模型有兩個方面轮蜕,其中一個方面依賴于另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和復(fù)用蝗锥。
一個對象的改變將導(dǎo)致其他一個或多個對象也發(fā)生改變跃洛,而不知道具體有多少對象將發(fā)生改變,可以降低對象之間的耦合度终议。
一個對象必須通知其他對象汇竭,而并不知道這些對象是誰。需要在系統(tǒng)中創(chuàng)建一個觸發(fā)鏈穴张,A對象的行為將影響B(tài)對象细燎,B對象的行為將影響C對象……,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機制皂甘。
注意事項: 1玻驻、JAVA 中已經(jīng)有了對觀察者模式的支持類。 2偿枕、避免循環(huán)引用璧瞬。 3、如果順序執(zhí)行渐夸,某一觀察者錯誤會導(dǎo)致系統(tǒng)卡殼嗤锉,一般采用異步方式。
迭代器模式
迭代器模式(Iterator Pattern)是 Java 和 .Net 編程環(huán)境中非常常用的設(shè)計模式墓塌。這種模式用于順序訪問集合對象的元素瘟忱,不需要知道集合對象的底層表示。
迭代器模式屬于行為型模式桃纯。
介紹
意圖:提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內(nèi)部表示酷誓。
主要解決:不同的方式來遍歷整個整合對象。
何時使用:遍歷一個聚合對象态坦。
如何解決:把在元素之間游走的責(zé)任交給迭代器盐数,而不是聚合對象。
關(guān)鍵代碼:定義接口:hasNext, next伞梯。
應(yīng)用實例:JAVA 中的 iterator玫氢。
優(yōu)點: 1、它支持以不同的方式遍歷一個聚合對象谜诫。 2漾峡、迭代器簡化了聚合類。 3喻旷、在同一個聚合上可以有多個遍歷生逸。 4、在迭代器模式中,增加新的聚合類和迭代器類都很方便槽袄,無須修改原有代碼烙无。
缺點:由于迭代器模式將存儲數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離,增加新的聚合類需要對應(yīng)增加新的迭代器類遍尺,類的個數(shù)成對增加截酷,這在一定程度上增加了系統(tǒng)的復(fù)雜性。
使用場景: 1乾戏、訪問一個聚合對象的內(nèi)容而無須暴露它的內(nèi)部表示迂苛。 2、需要為聚合對象提供多種遍歷方式鼓择。 3三幻、為遍歷不同的聚合結(jié)構(gòu)提供一個統(tǒng)一的接口。
注意事項:迭代器模式就是分離了集合對象的遍歷行為惯退,抽象出一個迭代器類來負(fù)責(zé)赌髓,這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu),又可讓外部代碼透明地訪問集合內(nèi)部的數(shù)據(jù)催跪。
責(zé)任鏈模式
顧名思義锁蠕,責(zé)任鏈模式(Chain of Responsibility Pattern)為請求創(chuàng)建了一個接收者對象的鏈。這種模式給予請求的類型懊蒸,對請求的發(fā)送者和接收者進行解耦荣倾。這種類型的設(shè)計模式屬于行為型模式。
在這種模式中骑丸,通常每個接收者都包含對另一個接收者的引用舌仍。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者通危,依此類推铸豁。
介紹
意圖:避免請求發(fā)送者與接收者耦合在一起,讓多個對象都有可能接收請求菊碟,將這些對象連接成一條鏈节芥,并且沿著這條鏈傳遞請求,直到有對象處理它為止逆害。
主要解決:職責(zé)鏈上的處理者負(fù)責(zé)處理請求头镊,客戶只需要將請求發(fā)送到職責(zé)鏈上即可,無須關(guān)心請求的處理細節(jié)和請求的傳遞魄幕,所以職責(zé)鏈將請求的發(fā)送者和請求的處理者解耦了相艇。
何時使用:在處理消息的時候以過濾很多道。
如何解決:攔截的類都實現(xiàn)統(tǒng)一接口纯陨。
關(guān)鍵代碼:Handler 里面聚合它自己坛芽,在 HanleRequest 里判斷是否合適留储,如果沒達到條件則向下傳遞,向誰傳遞之前 set 進去靡馁。
應(yīng)用實例: 1欲鹏、紅樓夢中的"擊鼓傳花"。 2臭墨、JS 中的事件冒泡。 3膘盖、JAVA WEB 中 Apache Tomcat 對 Encoding 的處理胧弛,Struts2 的攔截器,jsp servlet 的 Filter侠畔。
優(yōu)點: 1结缚、降低耦合度。它將請求的發(fā)送者和接收者解耦软棺。 2红竭、簡化了對象。使得對象不需要知道鏈的結(jié)構(gòu)喘落。 3茵宪、增強給對象指派職責(zé)的靈活性。通過改變鏈內(nèi)的成員或者調(diào)動它們的次序瘦棋,允許動態(tài)地新增或者刪除責(zé)任稀火。 4、增加新的請求處理類很方便赌朋。
缺點: 1凰狞、不能保證請求一定被接收。 2沛慢、系統(tǒng)性能將受到一定影響掂铐,而且在進行代碼調(diào)試時不太方便,可能會造成循環(huán)調(diào)用骇窍。 3祥诽、可能不容易觀察運行時的特征,有礙于除錯伐庭。
使用場景: 1粉渠、有多個對象可以處理同一個請求,具體哪個對象處理該請求由運行時刻自動確定圾另。 2霸株、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求集乔。 3去件、可動態(tài)指定一組對象處理請求坡椒。
注意事項:在 JAVA WEB 中遇到很多應(yīng)用。
命令模式
命令模式(Command Pattern)是一種數(shù)據(jù)驅(qū)動的設(shè)計模式尤溜,它屬于行為型模式倔叼。請求以命令的形式包裹在對象中,并傳給調(diào)用對象宫莱。調(diào)用對象尋找可以處理該命令的合適的對象丈攒,并把該命令傳給相應(yīng)的對象,該對象執(zhí)行命令授霸。
介紹
意圖:將一個請求封裝成一個對象巡验,從而使您可以用不同的請求對客戶進行參數(shù)化。
主要解決:在軟件系統(tǒng)中碘耳,行為請求者與行為實現(xiàn)者通常是一種緊耦合的關(guān)系显设,但某些場合,比如需要對行為進行記錄辛辨、撤銷或重做捕捂、事務(wù)等處理時,這種無法抵御變化的緊耦合的設(shè)計就不太合適斗搞。
何時使用:在某些場合指攒,比如要對行為進行"記錄、撤銷/重做榜旦、事務(wù)"等處理幽七,這種無法抵御變化的緊耦合是不合適的。在這種情況下溅呢,如何將"行為請求者"與"行為實現(xiàn)者"解耦澡屡?將一組行為抽象為對象,可以實現(xiàn)二者之間的松耦合咐旧。
如何解決:通過調(diào)用者調(diào)用接受者執(zhí)行命令驶鹉,順序:調(diào)用者→接受者→命令。
關(guān)鍵代碼:定義三個角色:1铣墨、received 真正的命令執(zhí)行對象 2室埋、Command 3、invoker 使用命令對象的入口
應(yīng)用實例:struts 1 中的 action 核心控制器 ActionServlet 只有一個伊约,相當(dāng)于 Invoker姚淆,而模型層的類會隨著不同的應(yīng)用有不同的模型類,相當(dāng)于具體的 Command屡律。
優(yōu)點: 1腌逢、降低了系統(tǒng)耦合度。 2超埋、新的命令可以很容易添加到系統(tǒng)中去搏讶。
缺點:使用命令模式可能會導(dǎo)致某些系統(tǒng)有過多的具體命令類佳鳖。
使用場景:認(rèn)為是命令的地方都可以使用命令模式,比如: 1媒惕、GUI 中每一個按鈕都是一條命令系吩。 2、模擬 CMD妒蔚。
注意事項:系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(fù)(Redo)操作穿挨,也可以考慮使用命令模式,見命令模式的擴展面睛。
備忘錄模式
備忘錄模式(Memento Pattern)保存一個對象的某個狀態(tài)絮蒿,以便在適當(dāng)?shù)臅r候恢復(fù)對象。備忘錄模式屬于行為型模式叁鉴。
介紹
意圖:在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài)佛寿,并在該對象之外保存這個狀態(tài)幌墓。
主要解決:所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內(nèi)部狀態(tài)冀泻,并在該對象之外保存這個狀態(tài)常侣,這樣可以在以后將對象恢復(fù)到原先保存的狀態(tài)。
何時使用:很多時候我們總是需要記錄一個對象的內(nèi)部狀態(tài)弹渔,這樣做的目的就是為了允許用戶取消不確定或者錯誤的操作胳施,能夠恢復(fù)到他原先的狀態(tài),使得他有"后悔藥"可吃肢专。
如何解決:通過一個備忘錄類專門存儲對象狀態(tài)舞肆。
關(guān)鍵代碼:客戶不與備忘錄類耦合,與備忘錄管理類耦合博杖。
應(yīng)用實例: 1椿胯、后悔藥。 2剃根、打游戲時的存檔哩盲。 3、Windows 里的 ctri + z狈醉。 4廉油、IE 中的后退。 4苗傅、數(shù)據(jù)庫的事務(wù)管理抒线。
優(yōu)點: 1、給用戶提供了一種可以恢復(fù)狀態(tài)的機制金吗,可以使用戶能夠比較方便地回到某個歷史的狀態(tài)十兢。 2趣竣、實現(xiàn)了信息的封裝,使得用戶不需要關(guān)心狀態(tài)的保存細節(jié)旱物。
缺點:消耗資源遥缕。如果類的成員變量過多,勢必會占用比較大的資源宵呛,而且每一次保存都會消耗一定的內(nèi)存单匣。
使用場景: 1、需要保存/恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場景宝穗。 2户秤、提供一個可回滾的操作。
注意事項: 1逮矛、為了符合迪米特原則鸡号,還要增加一個管理備忘錄的類。 2须鼎、為了節(jié)約內(nèi)存鲸伴,可使用原型模式+備忘錄模式。
狀態(tài)模式
在狀態(tài)模式(State Pattern)中晋控,類的行為是基于它的狀態(tài)改變的汞窗。這種類型的設(shè)計模式屬于行為型模式。
在狀態(tài)模式中赡译,我們創(chuàng)建表示各種狀態(tài)的對象和一個行為隨著狀態(tài)對象改變而改變的 context 對象仲吏。
介紹
意圖:允許對象在內(nèi)部狀態(tài)發(fā)生改變時改變它的行為,對象看起來好像修改了它的類蝌焚。
主要解決:對象的行為依賴于它的狀態(tài)(屬性)裹唆,并且可以根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為。
何時使用:代碼中包含大量與對象狀態(tài)有關(guān)的條件語句综看。
如何解決:將各種具體的狀態(tài)類抽象出來品腹。
關(guān)鍵代碼:通常命令模式的接口中只有一個方法。而狀態(tài)模式的接口中有一個或者多個方法红碑。而且舞吭,狀態(tài)模式的實現(xiàn)類的方法,一般返回值析珊,或者是改變實例變量的值羡鸥。也就是說,狀態(tài)模式一般和對象的狀態(tài)有關(guān)忠寻。實現(xiàn)類的方法有不同的功能惧浴,覆蓋接口中的方法。狀態(tài)模式和命令模式一樣奕剃,也可以用于消除 if...else 等條件選擇語句衷旅。
應(yīng)用實例: 1捐腿、打籃球的時候運動員可以有正常狀態(tài)、不正常狀態(tài)和超常狀態(tài)柿顶。 2茄袖、曾侯乙編鐘中,'鐘是抽象接口','鐘A'等是具體狀態(tài)嘁锯,'曾侯乙編鐘'是具體環(huán)境(Context)宪祥。
優(yōu)點: 1、封裝了轉(zhuǎn)換規(guī)則家乘。 2蝗羊、枚舉可能的狀態(tài),在枚舉狀態(tài)之前需要確定狀態(tài)種類仁锯。 3耀找、將所有與某個狀態(tài)有關(guān)的行為放到一個類中,并且可以方便地增加新的狀態(tài)业崖,只需要改變對象狀態(tài)即可改變對象的行為涯呻。 4、允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體腻要,而不是某一個巨大的條件語句塊。 5涝登、可以讓多個環(huán)境對象共享一個狀態(tài)對象雄家,從而減少系統(tǒng)中對象的個數(shù)。
缺點: 1胀滚、狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)趟济。 2、狀態(tài)模式的結(jié)構(gòu)與實現(xiàn)都較為復(fù)雜咽笼,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂顷编。 3、狀態(tài)模式對"開閉原則"的支持并不太好剑刑,對于可以切換狀態(tài)的狀態(tài)模式媳纬,增加新的狀態(tài)類需要修改那些負(fù)責(zé)狀態(tài)轉(zhuǎn)換的源代碼,否則無法切換到新增狀態(tài)施掏,而且修改某個狀態(tài)類的行為也需修改對應(yīng)類的源代碼钮惠。
使用場景: 1、行為隨狀態(tài)改變而改變的場景七芭。 2素挽、條件、分支語句的代替者狸驳。
注意事項:在行為受狀態(tài)約束的時候使用狀態(tài)模式预明,而且狀態(tài)不超過 5 個缩赛。
訪問者模式
在訪問者模式(Visitor Pattern)中,我們使用了一個訪問者類撰糠,它改變了元素類的執(zhí)行算法酥馍。通過這種方式,元素的執(zhí)行算法可以隨著訪問者改變而改變窗慎。這種類型的設(shè)計模式屬于行為型模式物喷。根據(jù)模式,元素對象已接受訪問者對象遮斥,這樣訪問者對象就可以處理元素對象上的操作峦失。
介紹
意圖:主要將數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作分離。
主要解決:穩(wěn)定的數(shù)據(jù)結(jié)構(gòu)和易變的操作耦合問題术吗。
何時使用:需要對一個對象結(jié)構(gòu)中的對象進行很多不同的并且不相關(guān)的操作尉辑,而需要避免讓這些操作"污染"這些對象的類,使用訪問者模式將這些封裝到類中较屿。
如何解決:在被訪問的類里面加一個對外提供接待訪問者的接口隧魄。
關(guān)鍵代碼:在數(shù)據(jù)基礎(chǔ)類里面有一個方法接受訪問者,將自身引用傳入訪問者隘蝎。
應(yīng)用實例:您在朋友家做客购啄,您是訪問者,朋友接受您的訪問嘱么,您通過朋友的描述狮含,然后對朋友的描述做出一個判斷,這就是訪問者模式曼振。
優(yōu)點: 1几迄、符合單一職責(zé)原則。 2冰评、優(yōu)秀的擴展性映胁。 3、靈活性甲雅。
缺點: 1解孙、具體元素對訪問者公布細節(jié),違反了迪米特原則务荆。 2妆距、具體元素變更比較困難。 3函匕、違反了依賴倒置原則娱据,依賴了具體類,沒有依賴抽象。
使用場景: 1中剩、對象結(jié)構(gòu)中對象對應(yīng)的類很少改變忌穿,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作。 2结啼、需要對一個對象結(jié)構(gòu)中的對象進行很多不同的并且不相關(guān)的操作掠剑,而需要避免讓這些操作"污染"這些對象的類,也不希望在增加新操作時修改這些類郊愧。
注意事項:訪問者可以對功能進行統(tǒng)一朴译,可以做報表、UI属铁、攔截器與過濾器眠寿。
中介者模式
中介者模式(Mediator Pattern)是用來降低多個對象和類之間的通信復(fù)雜性。這種模式提供了一個中介類焦蘑,該類通常處理不同類之間的通信盯拱,并支持松耦合,使代碼易于維護例嘱。中介者模式屬于行為型模式狡逢。
介紹
意圖:用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用拼卵,從而使其耦合松散奢浑,而且可以獨立地改變它們之間的交互。
主要解決:對象與對象之間存在大量的關(guān)聯(lián)關(guān)系腋腮,這樣勢必會導(dǎo)致系統(tǒng)的結(jié)構(gòu)變得很復(fù)雜殷费,同時若一個對象發(fā)生改變,我們也需要跟蹤與之相關(guān)聯(lián)的對象低葫,同時做出相應(yīng)的處理。
何時使用:多個類相互耦合仍律,形成了網(wǎng)狀結(jié)構(gòu)嘿悬。
如何解決:將上述網(wǎng)狀結(jié)構(gòu)分離為星型結(jié)構(gòu)。
關(guān)鍵代碼:對象 Colleague 之間的通信封裝到一個類中單獨處理水泉。
應(yīng)用實例: 1善涨、中國加入 WTO 之前是各個國家相互貿(mào)易,結(jié)構(gòu)復(fù)雜草则,現(xiàn)在是各個國家通過 WTO 來互相貿(mào)易钢拧。 2、機場調(diào)度系統(tǒng)炕横。 3源内、MVC 框架,其中C(控制器)就是 M(模型)和 V(視圖)的中介者份殿。
優(yōu)點: 1膜钓、降低了類的復(fù)雜度嗽交,將一對多轉(zhuǎn)化成了一對一。 2颂斜、各個類之間的解耦夫壁。 3、符合迪米特原則沃疮。
缺點:中介者會龐大盒让,變得復(fù)雜難以維護。
使用場景: 1司蔬、系統(tǒng)中對象之間存在比較復(fù)雜的引用關(guān)系邑茄,導(dǎo)致它們之間的依賴關(guān)系結(jié)構(gòu)混亂而且難以復(fù)用該對象。 2葱她、想通過一個中間類來封裝多個類中的行為撩扒,而又不想生成太多的子類。
注意事項:不應(yīng)當(dāng)在職責(zé)混亂的時候使用吨些。
解釋器模式
解釋器模式(Interpreter Pattern)提供了評估語言的語法或表達式的方式搓谆,它屬于行為型模式。這種模式實現(xiàn)了一個表達式接口豪墅,該接口解釋一個特定的上下文泉手。這種模式被用在 SQL 解析、符號處理引擎等偶器。
介紹
意圖:給定一個語言斩萌,定義它的文法表示,并定義一個解釋器屏轰,這個解釋器使用該標(biāo)識來解釋語言中的句子颊郎。
主要解決:對于一些固定文法構(gòu)建一個解釋句子的解釋器。
何時使用:如果一種特定類型的問題發(fā)生的頻率足夠高霎苗,那么可能就值得將該問題的各個實例表述為一個簡單語言中的句子姆吭。這樣就可以構(gòu)建一個解釋器,該解釋器通過解釋這些句子來解決該問題唁盏。
如何解決:構(gòu)件語法樹内狸,定義終結(jié)符與非終結(jié)符。
關(guān)鍵代碼:構(gòu)件環(huán)境類厘擂,包含解釋器之外的一些全局信息昆淡,一般是 HashMap。
應(yīng)用實例:編譯器刽严、運算表達式計算昂灵。
優(yōu)點: 1、可擴展性比較好,靈活倔既。 2恕曲、增加了新的解釋表達式的方式。 3渤涌、易于實現(xiàn)簡單文法佩谣。
缺點: 1、可利用場景比較少实蓬。 2茸俭、對于復(fù)雜的文法比較難維護。 3安皱、解釋器模式會引起類膨脹调鬓。 4、解釋器模式采用遞歸調(diào)用方法酌伊。
使用場景: 1腾窝、可以將一個需要解釋執(zhí)行的語言中的句子表示為一個抽象語法樹。 2居砖、一些重復(fù)出現(xiàn)的問題可以用一種簡單的語言來進行表達虹脯。 3、一個簡單語法需要解釋的場景奏候。