鏈接:https://github.com/WiKi123/DesignPattern
作者: WiKi123(github名稱)
設(shè)計模式代碼:由于篇幅有限,相關(guān)的設(shè)計模式代碼請移步到作者的github上下載:https://github.com/WiKi123/DesignPattern
本文分三部分介紹:
(1) 設(shè)計模式分為三大類
(2) 設(shè)計模式的六大原則
(3) 24種設(shè)計模式介紹
一: 設(shè)計模式分為三大類
創(chuàng)建型模式诊沪,共五種: 工廠方法模式、抽象工廠模式、單例模式、構(gòu)建者模式、原型模式。
結(jié)構(gòu)型模式,共七種: 適配器模式逊朽、裝飾器模式、代理模式曲伊、外觀模式叽讳、橋接模式、組合模式坟募、享元模式岛蚤。
行為型模式,共十一種: 策略模式懈糯、模板方法模式涤妒、觀察者模式、迭代器模式赚哗、責(zé)任鏈模式她紫、命令模式、備忘錄模式屿储、狀態(tài)模式贿讹、訪問者模式、中介者模式够掠、解釋器模式民褂。
其實(shí)還有兩類:并發(fā)型模式和線程池模式。
二: 設(shè)計模式的六大原則
總原則-開閉原則
對擴(kuò)展開放,對修改封閉赊堪。 在程序需要進(jìn)行拓展的時候面殖,不能去修改原有的代碼,而是要擴(kuò)展原有代碼哭廉,實(shí)現(xiàn)一個熱插拔的效果畜普。所以一句話概括就是:為了使程序的擴(kuò)展性好,易于維護(hù)和升級群叶。 想要達(dá)到這樣的效果,我們需要使用接口和抽象類等钝荡。
1街立、單一職責(zé)原則 不要存在多于一個導(dǎo)致類變更的原因,也就是說每個類應(yīng)該實(shí)現(xiàn)單一的職責(zé)埠通,否則就應(yīng)該把類拆分赎离。
2、里氏替換原則(Liskov Substitution Principle) 任何基類可以出現(xiàn)的地方端辱,子類一定可以出現(xiàn)梁剔。里氏替換原則是繼承復(fù)用的基石,只有當(dāng)衍生類可以替換基類舞蔽,軟件單位的功能不受到影響時荣病,基類才能真正被復(fù)用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為渗柿。 里氏代換原則是對“開-閉”原則的補(bǔ)充个盆。實(shí)現(xiàn)“開閉”原則的關(guān)鍵步驟就是抽象化。而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn)朵栖,所以里氏代換原則是對實(shí)現(xiàn)抽象化的具體步驟的規(guī)范颊亮。里氏替換原則中,子類對父類的方法盡量不要重寫和重載陨溅。因?yàn)楦割惔砹硕x好的結(jié)構(gòu)终惑,通過這個規(guī)范的接口與外界交互,子類不應(yīng)該隨便破壞它门扇。
3雹有、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle) 面向接口編程,依賴于抽象而不依賴于具體臼寄。寫代碼時用到具體類時件舵,不與具體類交互,而與具體類的上層接口交互脯厨。
4铅祸、接口隔離原則(Interface Segregation Principle) 每個接口中不存在子類用不到卻必須實(shí)現(xiàn)的方法,如果不然,就要將接口拆分临梗。使用多個隔離的接口涡扼,比使用單個接口(多個接口方法集合到一個的接口)要好。
5盟庞、迪米特法則(最少知道原則)(Demeter Principle) 一個類對自己依賴的類知道的越少越好吃沪。無論被依賴的類多么復(fù)雜,都應(yīng)該將邏輯封裝在方法的內(nèi)部什猖,通過public方法提供給外部票彪。這樣當(dāng)被依賴的類變化時,才能最小的影響該類不狮。 最少知道原則的另一個表達(dá)方式是:只與直接的朋友通信降铸。類之間只要有耦合關(guān)系,就叫朋友關(guān)系摇零。耦合分為依賴推掸、關(guān)聯(lián)、聚合驻仅、組合等谅畅。我們稱出現(xiàn)為成員變量、方法參數(shù)噪服、方法返回值中的類為直接朋友毡泻。局部變量、臨時變量則不是直接的朋友粘优。我們要求陌生的類不要作為局部變量出現(xiàn)在類中牙捉。
6、合成復(fù)用原則(Composite Reuse Principle) 盡量首先使用合成/聚合的方式敬飒,而不是使用繼承邪铲。
Thanks 溫杰. Thanks http://www.runoob.com/sitemap.
三 : 24種設(shè)計模式介紹
(A) 創(chuàng)建型模式
1.工廠模式
工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計模式之一。這種類型的設(shè)計模式屬于創(chuàng)建型模式无拗,它提供了一種創(chuàng)建對象的最佳方式带到。
在工廠模式中,我們在創(chuàng)建對象時不會對客戶端暴露創(chuàng)建邏輯英染,并且是通過使用一個共同的接口來指向新創(chuàng)建的對象揽惹。
介紹
意圖:
定義一個創(chuàng)建對象的接口,讓其子類自己決定實(shí)例化哪一個工廠類四康,工廠模式使其創(chuàng)建過程延遲到子類進(jìn)行搪搏。
主要解決:主要解決接口選擇的問題。
何時使用:我們明確地計劃不同條件下創(chuàng)建不同實(shí)例時闪金。
如何解決:讓其子類實(shí)現(xiàn)工廠接口疯溺,返回的也是一個抽象的產(chǎn)品论颅。
關(guān)鍵代碼:創(chuàng)建過程在其子類執(zhí)行。
應(yīng)用實(shí)例:
1囱嫩、您需要一輛汽車恃疯,可以直接從工廠里面提貨,而不用去管這輛汽車是怎么做出來的墨闲,以及這個汽車?yán)锩娴木唧w實(shí)現(xiàn)今妄。
2、Hibernate 換數(shù)據(jù)庫只需換方言和驅(qū)動就可以鸳碧。
優(yōu)點(diǎn):
1盾鳞、一個調(diào)用者想創(chuàng)建一個對象,只要知道其名稱就可以了瞻离。 2腾仅、擴(kuò)展性高,如果想增加一個產(chǎn)品琐脏,只要擴(kuò)展一個工廠類就可以。 3缸兔、屏蔽產(chǎn)品的具體實(shí)現(xiàn)日裙,調(diào)用者只關(guān)心產(chǎn)品的接口。
缺點(diǎn):
每次增加一個產(chǎn)品時惰蜜,都需要增加一個具體類和對象實(shí)現(xiàn)工廠昂拂,使得系統(tǒng)中類的個數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度抛猖,同時也增加了系統(tǒng)具體類的依賴格侯。這并不是什么好事。
使用場景:
1财著、日志記錄器:記錄可能記錄到本地硬盤联四、系統(tǒng)事件、遠(yuǎn)程服務(wù)器等撑教,用戶可以選擇記錄日志到什么地方朝墩。 2、數(shù)據(jù)庫訪問伟姐,當(dāng)用戶不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫收苏,以及數(shù)據(jù)庫可能有變化時。 3愤兵、設(shè)計一個連接服務(wù)器的框架鹿霸,需要三個協(xié)議,"POP3"秆乳、"IMAP"懦鼠、"HTTP",可以把這三個作為產(chǎn)品類,共同實(shí)現(xiàn)一個接口葛闷。
注意事項:
作為一種創(chuàng)建類模式憋槐,在任何需要生成復(fù)雜對象的地方,都可以使用工廠方法模式淑趾。有一點(diǎn)需要注意的地方就是復(fù)雜對象適合使用工廠模式阳仔,而簡單對象,特別是只需要通過 new 就可以完成創(chuàng)建的對象扣泊,無需使用工廠模式近范。如果使用工廠模式,就需要引入一個工廠類延蟹,會增加系統(tǒng)的復(fù)雜度评矩。
2.抽象工廠模式
抽象工廠模式(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)只消費(fèi)其中某一族的產(chǎn)品。
如何解決:在一個產(chǎn)品族里面预麸,定義多個產(chǎn)品瞪浸。
關(guān)鍵代碼:在一個工廠里聚合多個同類產(chǎn)品。
應(yīng)用實(shí)例:
工作了吏祸,為了參加一些聚會默终,肯定有兩套或多套衣服吧,比如說有商務(wù)裝(成套犁罩,一系列具體產(chǎn)品)齐蔽、時尚裝(成套,一系列具體產(chǎn)品)床估,甚至對于一個家庭來說含滴,可能有商務(wù)女裝、商務(wù)男裝丐巫、時尚女裝谈况、時尚男裝勺美,這些也都是成套的,即一系列具體產(chǎn)品碑韵。假設(shè)一種情況(現(xiàn)實(shí)中是不存在的赡茸,要不然,沒法進(jìn)入共產(chǎn)主義了祝闻,但有利于說明抽象工廠模式)占卧,在您的家中,某一個衣柜(具體工廠)只能存放某一種這樣的衣服(成套联喘,一系列具體產(chǎn)品)华蜒,每次拿這種成套的衣服時也自然要從這個衣柜中取出了。用 OO 的思想去理解豁遭,所有的衣柜(具體工廠)都是衣柜類的(抽象工廠)某一個叭喜,而每一件成套的衣服又包括具體的上衣(某一具體產(chǎn)品),褲子(某一具體產(chǎn)品)蓖谢,這些具體的上衣其實(shí)也都是上衣(抽象產(chǎn)品)捂蕴,具體的褲子也都是褲子(另一個抽象產(chǎn)品)。
優(yōu)點(diǎn):
當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時闪幽,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象啥辨。
缺點(diǎn):
產(chǎn)品族擴(kuò)展非常困難,要增加一個系列的某一產(chǎn)品沟使,既要在抽象的 Creator 里加代碼委可,又要在具體的里面加代碼渊跋。
使用場景:
1腊嗡、QQ 換皮膚,一整套一起換拾酝。 2燕少、生成不同操作系統(tǒng)的程序。
注意事項:
產(chǎn)品族難擴(kuò)展蒿囤,產(chǎn)品等級易擴(kuò)展客们。
3.單例模式
單例模式(Singleton Pattern)是 Java 中最簡單的設(shè)計模式之一。這種類型的設(shè)計模式屬于創(chuàng)建型模式材诽,它提供了一種創(chuàng)建對象的最佳方式底挫。
這種模式涉及到一個單一的類,該類負(fù)責(zé)創(chuàng)建自己的對象脸侥,同時確保只有單個對象被創(chuàng)建建邓。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問睁枕,不需要實(shí)例化該類的對象官边。
注意:
1沸手、單例類只能有一個實(shí)例。
2注簿、單例類必須自己創(chuàng)建自己的唯一實(shí)例契吉。
3、單例類必須給所有其他對象提供這一實(shí)例诡渴。
介紹
意圖:
保證一個類僅有一個實(shí)例捐晶,并提供一個訪問它的全局訪問點(diǎn)。
主要解決:一個全局使用的類頻繁地創(chuàng)建與銷毀玩徊。
何時使用:當(dāng)您想控制實(shí)例數(shù)目租悄,節(jié)省系統(tǒng)資源的時候。
如何解決:判斷系統(tǒng)是否已經(jīng)有這個單例恩袱,如果有則返回泣棋,如果沒有則創(chuàng)建。
關(guān)鍵代碼:構(gòu)造函數(shù)是私有的畔塔。
應(yīng)用實(shí)例:
1潭辈、一個黨只能有一個主席。 2澈吨、Windows 是多進(jìn)程多線程的把敢,在操作一個文件的時候,就不可避免地出現(xiàn)多個進(jìn)程或線程同時操作一個文件的現(xiàn)象谅辣,所以所有文件的處理必須通過唯一的實(shí)例來進(jìn)行修赞。 3、一些設(shè)備管理器常常設(shè)計為單例模式桑阶,比如一個電腦有兩臺打印機(jī)柏副,在輸出的時候就要處理不能兩臺打印機(jī)打印同一個文件。
優(yōu)點(diǎn):
1蚣录、在內(nèi)存里只有一個實(shí)例割择,減少了內(nèi)存的開銷,尤其是頻繁的創(chuàng)建和銷毀實(shí)例(比如管理學(xué)院首頁頁面緩存)萎河。 2荔泳、避免對資源的多重占用(比如寫文件操作)。
缺點(diǎn):
沒有接口虐杯,不能繼承玛歌,與單一職責(zé)原則沖突,一個類應(yīng)該只關(guān)心內(nèi)部邏輯擎椰,而不關(guān)心外面怎么樣來實(shí)例化支子。
使用場景:
1、要求生產(chǎn)唯一序列號确憨。 2译荞、WEB 中的計數(shù)器瓤的,不用每次刷新都在數(shù)據(jù)庫里加一次,用單例先緩存起來吞歼。 3圈膏、創(chuàng)建的一個對象需要消耗的資源過多,比如 I/O 與數(shù)據(jù)庫的連接等篙骡。
注意事項:getInstance() 方法中需要使用同步鎖 synchronized (Singleton.class) 防止多線程同時進(jìn)入造成 instance 被多次實(shí)例化稽坤。
4.建造者模(構(gòu)建者模式)
建造者模式(Builder Pattern)使用多個簡單的對象一步一步構(gòu)建成一個復(fù)雜的對象。這種類型的設(shè)計模式屬于創(chuàng)建型模式糯俗,它提供了一種創(chuàng)建對象的最佳方式尿褪。
一個 Builder 類會一步一步構(gòu)造最終的對象。該 Builder 類是獨(dú)立于其他對象的得湘。
介紹
意圖:
將一個復(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)建和提供實(shí)例思犁,導(dǎo)演:管理建造出來的實(shí)例的依賴關(guān)系代虾。
應(yīng)用實(shí)例:
1、去肯德基抒倚,漢堡褐着、可樂坷澡、薯條托呕、炸雞翅等是不變的,而其組合是經(jīng)常變化的频敛,生成出所謂的"套餐"项郊。
2、JAVA 中的 StringBuilder斟赚。
優(yōu)點(diǎn):
1着降、建造者獨(dú)立,易擴(kuò)展拗军。 2任洞、便于控制細(xì)節(jié)風(fēng)險蓄喇。
缺點(diǎn):
1、產(chǎn)品必須有共同點(diǎn)交掏,范圍有限制妆偏。 2、如內(nèi)部變化復(fù)雜盅弛,會有很多的建造類钱骂。
使用場景: 1、需要生成的對象具有復(fù)雜的內(nèi)部結(jié)構(gòu)挪鹏。 2见秽、需要生成的對象內(nèi)部屬性本身相互依賴。
注意事項:與工廠模式的區(qū)別是:建造者模式更加關(guān)注與零件裝配的順序讨盒。
5.原型模式
原型模式(Prototype Pattern)是用于創(chuàng)建重復(fù)的對象解取,同時又能保證性能。這種類型的設(shè)計模式屬于創(chuàng)建型模式返顺,它提供了一種創(chuàng)建對象的最佳方式肮蛹。
這種模式是實(shí)現(xiàn)了一個原型接口,該接口用于創(chuàng)建當(dāng)前對象的克隆创南。當(dāng)直接創(chuàng)建對象的代價比較大時伦忠,則采用這種模式。例如稿辙,一個對象需要在一個高代價的數(shù)據(jù)庫操作之后被創(chuàng)建昆码。我們可以緩存該對象,在下一個請求時返回它的克隆邻储,在需要的時候更新數(shù)據(jù)庫赋咽,以此來減少數(shù)據(jù)庫調(diào)用。
介紹
意圖:用原型實(shí)例指定創(chuàng)建對象的種類吨娜,并且通過拷貝這些原型創(chuàng)建新的對象脓匿。
主要解決:在運(yùn)行期建立和刪除原型。
何時使用:
1宦赠、當(dāng)一個系統(tǒng)應(yīng)該獨(dú)立于它的產(chǎn)品創(chuàng)建陪毡,構(gòu)成和表示時。
2勾扭、當(dāng)要實(shí)例化的類是在運(yùn)行時刻指定時毡琉,例如,通過動態(tài)裝載妙色。
3桅滋、為了避免創(chuàng)建一個與產(chǎn)品類層次平行的工廠類層次時。
4身辨、當(dāng)一個類的實(shí)例只能有幾個不同狀態(tài)組合中的一種時丐谋。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實(shí)例化該類更方便一些芍碧。
如何解決:利用已有的一個原型對象,快速地生成和原型對象一樣的實(shí)例号俐。
關(guān)鍵代碼:
1师枣、實(shí)現(xiàn)克隆操作,在 JAVA 繼承 Cloneable萧落,重寫 clone()践美,在 .NET 中可以使用 Object 類的 MemberwiseClone() 方法來實(shí)現(xiàn)對象的淺拷貝或通過序列化的方式來實(shí)現(xiàn)深拷貝。
2找岖、原型模式同樣用于隔離類對象的使用者和具體類型(易變類)之間的耦合關(guān)系陨倡,它同樣要求這些"易變類"擁有穩(wěn)定的接口。
應(yīng)用實(shí)例:
1许布、細(xì)胞分裂兴革。 2、JAVA 中的 Object clone() 方法蜜唾。
優(yōu)點(diǎn):
1杂曲、性能提高贡茅。 2屿良、逃避構(gòu)造函數(shù)的約束刀崖。
缺點(diǎn):
1颖榜、配備克隆方法需要對類的功能進(jìn)行通盤考慮棚饵,這對于全新的類不是很難,但對于已有的類不一定很容易掩完,特別當(dāng)一個類引用不支持串行化的間接對象噪漾,或者引用含有循環(huán)結(jié)構(gòu)的時候。
2且蓬、必須實(shí)現(xiàn) Cloneable 接口欣硼。
使用場景:
1、資源優(yōu)化場景恶阴。
2诈胜、類初始化需要消化非常多的資源,這個資源包括數(shù)據(jù)存淫、硬件資源等耘斩。
3沼填、性能和安全要求的場景桅咆。
4、通過 new 產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限坞笙,則可以使用原型模式岩饼。
5荚虚、一個對象多個修改者的場景。
6籍茧、一個對象需要提供給其他對象訪問版述,而且各個調(diào)用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調(diào)用者使用寞冯。
7渴析、在實(shí)際項目中,原型模式很少單獨(dú)出現(xiàn)吮龄,一般是和工廠方法模式一起出現(xiàn)俭茧,通過 clone 的方法創(chuàng)建一個對象,然后由工廠方法提供給調(diào)用者漓帚。原型模式已經(jīng)與 Java 融為渾然一體母债,大家可以隨手拿來使用。
注意事項:
與通過對一個類進(jìn)行實(shí)例化來構(gòu)造新對象不同的是尝抖,原型模式是通過拷貝一個現(xiàn)有對象生成新對象的毡们。淺拷貝實(shí)現(xiàn) Cloneable,重寫昧辽,深拷貝是通過實(shí)現(xiàn) Serializable 讀取二進(jìn)制流衙熔。
(B)結(jié)構(gòu)型模式
6.適配器模式
適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式搅荞,它結(jié)合了兩個獨(dú)立接口的功能青责。
這種模式涉及到一個單一的類,該類負(fù)責(zé)加入獨(dú)立的或不兼容的接口功能取具。舉個真實(shí)的例子脖隶,讀卡器是作為內(nèi)存卡和筆記本之間的適配器。您將內(nèi)存卡插入讀卡器暇检,再將讀卡器插入筆記本产阱,這樣就可以通過筆記本來讀取內(nèi)存卡。
我們通過下面的實(shí)例來演示適配器模式的使用块仆。其中构蹬,音頻播放器設(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)的一些類期吓,包括一些可能在將來引進(jìn)的類一起工作,這些源類不一定有一致的接口倾芝。
3讨勤、通過接口轉(zhuǎn)換,將一個類插入另一個類系中晨另。(比如老虎和飛禽悬襟,現(xiàn)在多了一個飛虎,在不增加實(shí)體的需求下拯刁,增加一個適配器脊岳,在里面包容一個虎對象,實(shí)現(xiàn)飛的接口垛玻。)
如何解決:繼承或依賴(推薦)割捅。
關(guān)鍵代碼:適配器繼承或依賴已有的對象,實(shí)現(xiàn)想要的目標(biāo)接口帚桩。
應(yīng)用實(shí)例:
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 上運(yùn)行 WINDOWS 程序涨岁。
4拐袜、JAVA 中的 jdbc。
優(yōu)點(diǎn):
1梢薪、可以讓任何兩個沒有關(guān)聯(lián)的類一起運(yùn)行蹬铺。
2、提高了類的復(fù)用秉撇。
3甜攀、增加了類的透明度秋泄。
4、靈活性好赴邻。
缺點(diǎn):
1印衔、過多地使用適配器啡捶,會讓系統(tǒng)非常零亂姥敛,不易整體進(jìn)行把握。比如瞎暑,明明看到調(diào)用的是 A 接口彤敛,其實(shí)內(nèi)部被適配成了 B 接口的實(shí)現(xiàn),一個系統(tǒng)如果太多出現(xiàn)這種情況了赌,無異于一場災(zāi)難墨榄。因此如果不是很有必要,可以不使用適配器勿她,而是直接對系統(tǒng)進(jìn)行重構(gòu)袄秩。
2.由于 JAVA 至多繼承一個類,所以至多只能適配一個適配者類逢并,而且目標(biāo)類必須是抽象類之剧。
使用場景:有動機(jī)地修改一個正常運(yùn)行的系統(tǒng)的接口,這時應(yīng)該考慮使用適配器模式砍聊。
注意事項:適配器不是在詳細(xì)設(shè)計時添加的背稼,而是解決正在服役的項目的問題。
7.裝飾器模式
裝飾器模式(Decorator Pattern)允許向一個現(xiàn)有的對象添加新的功能玻蝌,同時又不改變其結(jié)構(gòu)蟹肘。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個包裝俯树。
這種模式創(chuàng)建了一個裝飾類帘腹,用來包裝原有的類,并在保持類方法簽名完整性的前提下许饿,提供了額外的功能竹椒。
我們通過下面的實(shí)例來演示裝飾器模式的用法。其中米辐,我們將把一個形狀裝飾上不同的顏色胸完,同時又不改變形狀類。
介紹
意圖:
動態(tài)地給一個對象添加一些額外的職責(zé)翘贮。就增加功能來說赊窥,裝飾器模式相比生成子類更為靈活。
主要解決:
一般的狸页,我們?yōu)榱藬U(kuò)展一個類經(jīng)常使用繼承方式實(shí)現(xiàn)锨能,由于繼承為類引入靜態(tài)特征扯再,并且隨著擴(kuò)展功能的增多,子類會很膨脹址遇。
何時使用:
在不想增加很多子類的情況下擴(kuò)展類熄阻。
如何解決:
將具體功能職責(zé)劃分,同時繼承裝飾者模式倔约。
關(guān)鍵代碼:
1秃殉、Component 類充當(dāng)抽象角色,不應(yīng)該具體實(shí)現(xiàn)浸剩。
2钾军、修飾類引用和繼承 Component 類,具體擴(kuò)展類重寫父類方法绢要。
應(yīng)用實(shí)例:
1吏恭、孫悟空有 72 變,當(dāng)他變成"廟宇"后重罪,他的根本還是一只猴子樱哼,但是他又有了廟宇的功能。
2剿配、不論一幅畫有沒有畫框都可以掛在墻上搅幅,但是通常都是有畫框的,并且實(shí)際上是畫框被掛在墻上惨篱。在掛在墻上之前盏筐,畫可以被蒙上玻璃,裝到框子里砸讳;這時畫琢融、玻璃和畫框形成了一個物體。
優(yōu)點(diǎn):
裝飾類和被裝飾類可以獨(dú)立發(fā)展簿寂,不會相互耦合漾抬,裝飾模式是繼承的一個替代模式,裝飾模式可以動態(tài)擴(kuò)展一個實(shí)現(xiàn)類的功能常遂。
缺點(diǎn):
多層裝飾比較復(fù)雜纳令。
使用場景:
1、擴(kuò)展一個類的功能克胳。 2平绩、動態(tài)增加功能,動態(tài)撤銷漠另。
注意事項:可代替繼承捏雌。
8.代理模式
在代理模式(Proxy Pattern)中,一個類代表另一個類的功能笆搓。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式性湿。
在代理模式中纬傲,我們創(chuàng)建具有現(xiàn)有對象的對象,以便向外界提供功能接口肤频。
介紹
意圖:
為其他對象提供一種代理以控制對這個對象的訪問叹括。
主要解決:
在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠(yuǎn)程的機(jī)器上宵荒。在面向?qū)ο笙到y(tǒng)中汁雷,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制骇扇,或者需要進(jìn)程外的訪問)摔竿,直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩面粮,我們可以在訪問此對象時加上一個對此對象的訪問層少孝。
何時使用:想在訪問一個類時做一些控制。
如何解決:增加中間層熬苍。
關(guān)鍵代碼:實(shí)現(xiàn)與被代理類組合稍走。
應(yīng)用實(shí)例:
1、Windows 里面的快捷方式柴底。
2婿脸、豬八戒去找高翠蘭結(jié)果是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來柄驻,高翠蘭本人和孫悟空都實(shí)現(xiàn)了這個接口狐树,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,所以說孫悟空是高翠蘭代理類鸿脓。
3抑钟、買火車票不一定在火車站買,也可以去代售點(diǎn)野哭。
4在塔、一張支票或銀行存單是賬戶中資金的代理。支票在市場交易中用來代替現(xiàn)金拨黔,并提供對簽發(fā)人賬號上資金的控制蛔溃。
5、spring aop篱蝇。
優(yōu)點(diǎn):
1贺待、職責(zé)清晰。 2零截、高擴(kuò)展性麸塞。 3、智能化瞻润。
缺點(diǎn):
1喘垂、由于在客戶端和真實(shí)主題之間增加了代理對象甜刻,因此有些類型的代理模式可能會造成請求的處理速度變慢。 2正勒、實(shí)現(xiàn)代理模式需要額外的工作得院,有些代理模式的實(shí)現(xiàn)非常復(fù)雜。
使用場景:
按職責(zé)來劃分章贞,通常有以下使用場景:
1祥绞、遠(yuǎn)程代理。 2鸭限、虛擬代理蜕径。 3、Copy-on-Write 代理败京。 4兜喻、保護(hù)(Protect or Access)代理。 5赡麦、Cache代理朴皆。 6、防火墻(Firewall)代理泛粹。 7遂铡、同步化(Synchronization)代理。 8晶姊、智能引用(Smart Reference)代理扒接。
注意事項:
1、和適配器模式的區(qū)別:適配器模式主要改變所考慮對象的接口们衙,而代理模式不能改變所代理類的接口钾怔。
2、和裝飾器模式的區(qū)別:裝飾器模式為了增強(qiáng)功能砍艾,而代理模式是為了加以控制蒂教。
9.外觀模式
外觀模式(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ù)雜度观堂,簡化客戶端與之的接口让网。
何時使用:
1呀忧、客戶端不需要知道系統(tǒng)內(nèi)部的復(fù)雜聯(lián)系,整個系統(tǒng)只需提供一個"接待員"即可溃睹。
2而账、定義系統(tǒng)的入口。
如何解決:
客戶端不與系統(tǒng)耦合因篇,外觀類與系統(tǒng)耦合泞辐。
關(guān)鍵代碼:
在客戶端和復(fù)雜系統(tǒng)之間再加一層,這一層將調(diào)用順序竞滓、依賴關(guān)系等處理好咐吼。
應(yīng)用實(shí)例:
1、去醫(yī)院看病商佑,可能要去掛號锯茄、門診、劃價莉御、取藥撇吞,讓患者或患者家屬覺得很復(fù)雜俗冻,如果有提供接待人員礁叔,只讓接待人員來處理,就很方便迄薄。
2琅关、JAVA 的三層開發(fā)模式。
優(yōu)點(diǎn):
1讥蔽、減少系統(tǒng)相互依賴涣易。 2、提高靈活性冶伞。 3新症、提高了安全性。
缺點(diǎn):
不符合開閉原則响禽,如果要改東西很麻煩徒爹,繼承重寫都不合適。
使用場景:
1芋类、為復(fù)雜的模塊或子系統(tǒng)提供外界訪問的模塊隆嗅。
2、子系統(tǒng)相對獨(dú)立侯繁。
3胖喳、預(yù)防低水平人員帶來的風(fēng)險。
注意事項:
在層次化結(jié)構(gòu)中贮竟,可以使用外觀模式定義系統(tǒng)中每一層的入口丽焊。
10.橋接模式
橋接(Bridge)是用于把抽象化與實(shí)現(xiàn)化解耦较剃,使得二者可以獨(dú)立變化。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式技健,它通過提供抽象化和實(shí)現(xiàn)化之間的橋接結(jié)構(gòu)重付,來實(shí)現(xiàn)二者的解耦。
這種模式涉及到一個作為橋接的接口凫乖,使得實(shí)體類的功能獨(dú)立于接口實(shí)現(xiàn)類确垫。這兩種類型的類可被結(jié)構(gòu)化改變而互不影響。
我們通過下面的實(shí)例來演示橋接模式(Bridge Pattern)的用法帽芽。其中删掀,可以使用相同的抽象類方法但是不同的橋接實(shí)現(xiàn)類,來畫出不同顏色的圓导街。
介紹
意圖:
將抽象部分與實(shí)現(xiàn)部分分離披泪,使它們都可以獨(dú)立的變化。
主要解決:
在有多種可能會變化的情況下搬瑰,用繼承會造成類爆炸問題款票,擴(kuò)展起來不靈活。
何時使用:
實(shí)現(xiàn)系統(tǒng)可能有多個角度分類泽论,每一種角度都可能變化艾少。
如何解決:
把這種多角度分類分離出來,讓它們獨(dú)立變化翼悴,減少它們之間耦合缚够。
關(guān)鍵代碼:
抽象類依賴實(shí)現(xiàn)類。
應(yīng)用實(shí)例:
1鹦赎、豬八戒從天蓬元帥轉(zhuǎn)世投胎到豬谍椅,轉(zhuǎn)世投胎的機(jī)制將塵世劃分為兩個等級,即:靈魂和肉體古话,前者相當(dāng)于抽象化雏吭,后者相當(dāng)于實(shí)現(xiàn)化。生靈通過功能的委派陪踩,調(diào)用肉體對象的功能杖们,使得生靈可以動態(tài)地選擇。
2膊毁、墻上的開關(guān)胀莹,可以看到的開關(guān)是抽象的,不用管里面具體怎么實(shí)現(xiàn)的婚温。
優(yōu)點(diǎn):
1描焰、抽象和實(shí)現(xiàn)的分離。
2、優(yōu)秀的擴(kuò)展能力荆秦。
3篱竭、實(shí)現(xiàn)細(xì)節(jié)對客戶透明。
缺點(diǎn):
橋接模式的引入會增加系統(tǒng)的理解與設(shè)計難度步绸,由于聚合關(guān)聯(lián)關(guān)系建立在抽象層掺逼,要求開發(fā)者針對抽象進(jìn)行設(shè)計與編程。
使用場景:
1瓤介、如果一個系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性吕喘,避免在兩個層次之間建立靜態(tài)的繼承聯(lián)系,通過橋接模式可以使它們在抽象層建立一個關(guān)聯(lián)關(guān)系刑桑。
2氯质、對于那些不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個數(shù)急劇增加的系統(tǒng),橋接模式尤為適用祠斧。
3闻察、一個類存在兩個獨(dú)立變化的維度,且這兩個維度都需要進(jìn)行擴(kuò)展琢锋。
注意事項:
對于兩個獨(dú)立變化的維度辕漂,使用橋接模式再適合不過了。
11.組合模式
組合模式(Composite Pattern)吴超,又叫部分整體模式钉嘹,是用于把一組相似的對象當(dāng)作一個單一的對象。組合模式依據(jù)樹形結(jié)構(gòu)來組合對象烛芬,用來表示部分以及整體層次隧期。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它創(chuàng)建了對象組的樹形結(jié)構(gòu)赘娄。
這種模式創(chuàng)建了一個包含自己對象組的類。該類提供了修改相同對象組的方式宏蛉。
我們通過下面的實(shí)例來演示組合模式的用法遣臼。實(shí)例演示了一個組織中員工的層次結(jié)構(gòu)。
介紹
意圖:
將對象組合成樹形結(jié)構(gòu)以表示"部分-整體"的層次結(jié)構(gòu)拾并。組合模式使得用戶對單個對象和組合對象的使用具有一致性揍堰。
主要解決:
它在我們樹型結(jié)構(gòu)的問題中,模糊了簡單元素和復(fù)雜元素的概念嗅义,客戶程序可以向處理簡單元素一樣來處理復(fù)雜元素屏歹,從而使得客戶程序與復(fù)雜元素的內(nèi)部結(jié)構(gòu)解耦。
何時使用:
1之碗、您想表示對象的部分-整體層次結(jié)構(gòu)(樹形結(jié)構(gòu))蝙眶。
2、您希望用戶忽略組合對象與單個對象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對象幽纷。
如何解決:
樹枝和葉子實(shí)現(xiàn)統(tǒng)一接口式塌,樹枝內(nèi)部組合該接口。
關(guān)鍵代碼:
樹枝內(nèi)部組合該接口友浸,并且含有內(nèi)部屬性 List峰尝,里面放 Component。
應(yīng)用實(shí)例:
1收恢、算術(shù)表達(dá)式包括操作數(shù)武学、操作符和另一個操作數(shù),其中伦意,另一個操作符也可以是操作數(shù)劳淆、操作符和另一個操作數(shù)。
2默赂、在 JAVA AWT 和 SWING 中沛鸵,對于 Button 和 Checkbox 是樹葉,Container 是樹枝缆八。
優(yōu)點(diǎn):
1曲掰、高層模塊調(diào)用簡單。
2奈辰、節(jié)點(diǎn)自由增加栏妖。
缺點(diǎn):
在使用組合模式時,其葉子和樹枝的聲明都是實(shí)現(xiàn)類奖恰,而不是接口吊趾,違反了依賴倒置原則。
使用場景:
部分瑟啃、整體場景论泛,如樹形菜單,文件蛹屿、文件夾的管理黍檩。
注意事項:
定義時為具體類获搏。
12.享元模式
享元模式(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 對象。
介紹
意圖:
運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對象怕享。
主要解決:
在有大量對象時执赡,有可能會造成內(nèi)存溢出,我們把其中共同的部分抽象出來函筋,如果有相同的業(yè)務(wù)請求沙合,直接返回在內(nèi)存中已有的對象,避免重新創(chuàng)建跌帐。
何時使用:
1首懈、系統(tǒng)中有大量對象。
2谨敛、這些對象消耗大量內(nèi)存究履。
3、這些對象的狀態(tài)大部分可以外部化脸狸。
4最仑、這些對象可以按照內(nèi)蘊(yùn)狀態(tài)分為很多組,當(dāng)把外蘊(yùn)對象從對象中剔除出來時炊甲,每一組對象都可以用一個對象來代替泥彤。
5、系統(tǒng)不依賴于這些對象身份卿啡,這些對象是不可分辨的吟吝。
如何解決:
用唯一標(biāo)識碼判斷,如果在內(nèi)存中有颈娜,則返回這個唯一標(biāo)識碼所標(biāo)識的對象剑逃。
關(guān)鍵代碼:
用 HashMap 存儲這些對象。
應(yīng)用實(shí)例:
1官辽、JAVA 中的 String蛹磺,如果有則返回,如果沒有則創(chuàng)建一個字符串保存在字符串緩存池里面野崇。
2称开、數(shù)據(jù)庫的數(shù)據(jù)池。
優(yōu)點(diǎn):
大大減少對象的創(chuàng)建乓梨,降低系統(tǒng)的內(nèi)存,使效率提高清酥。
缺點(diǎn):
提高了系統(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臣镣、這些類必須有一個工廠對象加以控制辅愿。
(C)行為型模式
13.策略模式
在策略模式(Strategy Pattern)中,一個類的行為或其算法可以在運(yùn)行時更改忆某。這種類型的設(shè)計模式屬于行為型模式点待。
在策略模式中,我們創(chuàng)建表示各種策略的對象和一個行為隨著策略對象改變而改變的 context 對象弃舒。策略對象改變 context 對象的執(zhí)行算法癞埠。
介紹
意圖:
定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換。
主要解決:
在有多種算法相似的情況下聋呢,使用 if...else 所帶來的復(fù)雜和難以維護(hù)苗踪。
何時使用:
一個系統(tǒng)有許多許多類,而區(qū)分它們的只是他們直接的行為坝冕。
如何解決:
將這些算法封裝成一個一個的類徒探,任意地替換。
關(guān)鍵代碼:
實(shí)現(xiàn)同一個接口喂窟。
應(yīng)用實(shí)例:
1测暗、諸葛亮的錦囊妙計,每一個錦囊就是一個策略磨澡。
2碗啄、旅行的出游方式,選擇騎自行車稳摄、坐汽車稚字,每一種旅行方式都是一個策略。
3厦酬、JAVA AWT 中的 LayoutManager胆描。
優(yōu)點(diǎn):
1、算法可以自由切換仗阅。
2昌讲、避免使用多重條件判斷。
3减噪、擴(kuò)展性良好短绸。
缺點(diǎn):
1车吹、策略類會增多。
2醋闭、所有策略類都需要對外暴露窄驹。
使用場景:
1、如果在一個系統(tǒng)里面有許多類证逻,它們之間的區(qū)別僅在于它們的行為乐埠,那么使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為。
2瑟曲、一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種饮戳。
3、如果一個對象有很多的行為洞拨,如果不用恰當(dāng)?shù)哪J匠豆蓿@些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)。
注意事項:
如果一個系統(tǒng)的策略多于四個烦衣,就需要考慮使用混合模式歹河,解決策略類膨脹的問題。
14.模板模式
在模板模式(Template Pattern)中花吟,一個抽象類公開定義了執(zhí)行它的方法的方式/模板秸歧。它的子類可以按需要重寫方法實(shí)現(xiàn),但調(diào)用將以抽象類中定義的方式進(jìn)行衅澈。這種類型的設(shè)計模式屬于行為型模式键菱。
介紹
意圖:
定義一個操作中的算法的骨架,而將一些步驟延遲到子類中今布。模板方法使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟经备。
主要解決:
一些方法通用,卻在每一個子類都重新寫了這一方法部默。
何時使用:
有一些通用的方法侵蒙。
如何解決:
將這些通用算法抽象出來。
關(guān)鍵代碼:
在抽象類實(shí)現(xiàn)傅蹂,其他步驟在子類實(shí)現(xiàn)纷闺。
應(yīng)用實(shí)例:
1、在造房子的時候份蝴,地基犁功、走線、水管都一樣婚夫,只有在建筑的后期才有加壁櫥加?xùn)艡诘炔町悺?/p>
2波桩、西游記里面菩薩定好的 81 難,這就是一個頂層的邏輯骨架请敦。
3镐躲、spring 中對 Hibernate 的支持,將一些已經(jīng)定好的方法封裝起來侍筛,比如開啟事務(wù)萤皂、獲取 Session、關(guān)閉 Session 等匣椰,程序員不重復(fù)寫那些已經(jīng)規(guī)范好的代碼裆熙,直接丟一個實(shí)體就可以保存。
優(yōu)點(diǎn):
1禽笑、封裝不變部分入录,擴(kuò)展可變部分。
2佳镜、提取公共代碼僚稿,便于維護(hù)。
3蟀伸、行為由父類控制蚀同,子類實(shí)現(xiàn)。
缺點(diǎn):
每一個不同的實(shí)現(xiàn)都需要一個子類來實(shí)現(xiàn)啊掏,導(dǎo)致類的個數(shù)增加蠢络,使得系統(tǒng)更加龐大。
使用場景:
1迟蜜、有多個子類共有的方法刹孔,且邏輯相同。
2娜睛、重要的髓霞、復(fù)雜的方法,可以考慮作為模板方法微姊。
注意事項:
為防止惡意操作酸茴,一般模板方法都加上 final 關(guān)鍵詞。
15.觀察者模式
當(dāng)對象間存在一對多關(guān)系時兢交,則使用觀察者模式(Observer Pattern)薪捍。比如,當(dāng)一個對象被修改時配喳,則會自動通知它的依賴對象酪穿。觀察者模式屬于行為型模式。
介紹
意圖:
定義對象間的一種一對多的依賴關(guān)系晴裹,當(dāng)一個對象的狀態(tài)發(fā)生改變時被济,所有依賴于它的對象都得到通知并被自動更新。
主要解決:
一個對象狀態(tài)改變給其他對象通知的問題涧团,而且要考慮到易用和低耦合只磷,保證高度的協(xié)作经磅。
何時使用:
一個對象(目標(biāo)對象)的狀態(tài)發(fā)生改變,所有的依賴對象(觀察者對象)都將得到通知钮追,進(jìn)行廣播通知预厌。
如何解決:
使用面向?qū)ο蠹夹g(shù),可以將這種依賴關(guān)系弱化元媚。
關(guān)鍵代碼:
在抽象類里有一個 ArrayList 存放觀察者們轧叽。
應(yīng)用實(shí)例:
1、拍賣的時候刊棕,拍賣師觀察最高標(biāo)價炭晒,然后通知給其他競價者競價。
2甥角、西游記里面悟空請求菩薩降服紅孩兒网严,菩薩灑了一地水招來一個老烏龜,這個烏龜就是觀察者蜈膨,他觀察菩薩灑水這個動作屿笼。
優(yōu)點(diǎn):
1、觀察者和被觀察者是抽象耦合的翁巍。
2驴一、建立一套觸發(fā)機(jī)制。
缺點(diǎn):
1灶壶、如果一個被觀察者對象有很多的直接和間接的觀察者的話肝断,將所有的觀察者都通知到會花費(fèi)很多時間。
2驰凛、如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話胸懈,觀察目標(biāo)會觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰恰响。
3趣钱、觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化胚宦。
使用場景:
一個抽象模型有兩個方面首有,其中一個方面依賴于另一個方面。將這些方面封裝在獨(dú)立的對象中使它們可以各自獨(dú)立地改變和復(fù)用枢劝。
一個對象的改變將導(dǎo)致其他一個或多個對象也發(fā)生改變井联,而不知道具體有多少對象將發(fā)生改變,可以降低對象之間的耦合度您旁。
一個對象必須通知其他對象烙常,而并不知道這些對象是誰。
需要在系統(tǒng)中創(chuàng)建一個觸發(fā)鏈鹤盒,A對象的行為將影響B(tài)對象蚕脏,B對象的行為將影響C對象……侦副,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機(jī)制。
注意事項:
1蝗锥、JAVA 中已經(jīng)有了對觀察者模式的支持類跃洛。
2、避免循環(huán)引用终议。
3、如果順序執(zhí)行葱蝗,某一觀察者錯誤會導(dǎo)致系統(tǒng)卡殼穴张,一般采用異步方式。
16.迭代器模式
迭代器模式(Iterator Pattern)是 Java 和 .Net 編程環(huán)境中非常常用的設(shè)計模式两曼。這種模式用于順序訪問集合對象的元素皂甘,不需要知道集合對象的底層表示。
迭代器模式屬于行為型模式悼凑。
介紹
意圖:
提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內(nèi)部表示偿枕。
主要解決:
不同的方式來遍歷整個整合對象。
何時使用:
遍歷一個聚合對象户辫。
如何解決:
把在元素之間游走的責(zé)任交給迭代器渐夸,而不是聚合對象。
關(guān)鍵代碼:
定義接口:hasNext, next渔欢。
應(yīng)用實(shí)例:
JAVA 中的 iterator墓塌。
優(yōu)點(diǎn):
1、它支持以不同的方式遍歷一個聚合對象奥额。
2苫幢、迭代器簡化了聚合類。
3垫挨、在同一個聚合上可以有多個遍歷韩肝。
4、在迭代器模式中九榔,增加新的聚合類和迭代器類都很方便哀峻,無須修改原有代碼。
缺點(diǎn):
由于迭代器模式將存儲數(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ù)涮拗。
17.責(zé)任鏈模式
顧名思義乾戏,責(zé)任鏈模式(Chain of Responsibility Pattern)為請求創(chuàng)建了一個接收者對象的鏈。這種模式給予請求的類型三热,對請求的發(fā)送者和接收者進(jìn)行解耦鼓择。這種類型的設(shè)計模式屬于行為型模式。
在這種模式中就漾,通常每個接收者都包含對另一個接收者的引用呐能。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者抑堡,依此類推摆出。
介紹
意圖:
避免請求發(fā)送者與接收者耦合在一起,讓多個對象都有可能接收請求首妖,將這些對象連接成一條鏈偎漫,并且沿著這條鏈傳遞請求,直到有對象處理它為止悯搔。
主要解決:
職責(zé)鏈上的處理者負(fù)責(zé)處理請求骑丸,客戶只需要將請求發(fā)送到職責(zé)鏈上即可,無須關(guān)心請求的處理細(xì)節(jié)和請求的傳遞妒貌,所以職責(zé)鏈將請求的發(fā)送者和請求的處理者解耦了通危。
何時使用:
在處理消息的時候以過濾很多道。
如何解決:
攔截的類都實(shí)現(xiàn)統(tǒng)一接口灌曙。
關(guān)鍵代碼:
Handler 里面聚合它自己菊碟,在 HanleRequest 里判斷是否合適,如果沒達(dá)到條件則向下傳遞在刺,向誰傳遞之前 set 進(jìn)去逆害。
應(yīng)用實(shí)例:
1、紅樓夢中的"擊鼓傳花"蚣驼。
2魄幕、JS 中的事件冒泡。
3颖杏、JAVA WEB 中 Apache Tomcat 對 Encoding 的處理纯陨,Struts2 的攔截器,jsp servlet 的 Filter。
優(yōu)點(diǎn):
1翼抠、降低耦合度咙轩。它將請求的發(fā)送者和接收者解耦。
2阴颖、簡化了對象活喊。使得對象不需要知道鏈的結(jié)構(gòu)。
3量愧、增強(qiáng)給對象指派職責(zé)的靈活性钾菊。通過改變鏈內(nèi)的成員或者調(diào)動它們的次序,允許動態(tài)地新增或者刪除責(zé)任侠畔。
4结缚、增加新的請求處理類很方便。
缺點(diǎn):
1软棺、不能保證請求一定被接收。
2尤勋、系統(tǒng)性能將受到一定影響喘落,而且在進(jìn)行代碼調(diào)試時不太方便,可能會造成循環(huán)調(diào)用最冰。
3瘦棋、可能不容易觀察運(yùn)行時的特征,有礙于除錯暖哨。
使用場景:
1赌朋、有多個對象可以處理同一個請求,具體哪個對象處理該請求由運(yùn)行時刻自動確定篇裁。
2沛慢、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求达布。
3团甲、可動態(tài)指定一組對象處理請求。
注意事項:
在 JAVA WEB 中遇到很多應(yīng)用黍聂。
18.命令模式
命令模式(Command Pattern)是一種數(shù)據(jù)驅(qū)動的設(shè)計模式躺苦,它屬于行為型模式。請求以命令的形式包裹在對象中产还,并傳給調(diào)用對象匹厘。調(diào)用對象尋找可以處理該命令的合適的對象,并把該命令傳給相應(yīng)的對象脐区,該對象執(zhí)行命令愈诚。
介紹
意圖:
將一個請求封裝成一個對象,從而使您可以用不同的請求對客戶進(jìn)行參數(shù)化。
主要解決:
在軟件系統(tǒng)中扰路,行為請求者與行為實(shí)現(xiàn)者通常是一種緊耦合的關(guān)系尤溜,但某些場合,比如需要對行為進(jìn)行記錄汗唱、撤銷或重做宫莱、事務(wù)等處理時,這種無法抵御變化的緊耦合的設(shè)計就不太合適哩罪。
何時使用:
在某些場合授霸,比如要對行為進(jìn)行"記錄、撤銷/重做际插、事務(wù)"等處理碘耳,這種無法抵御變化的緊耦合是不合適的。在這種情況下框弛,如何將"行為請求者"與"行為實(shí)現(xiàn)者"解耦辛辨?將一組行為抽象為對象,可以實(shí)現(xiàn)二者之間的松耦合瑟枫。
如何解決:
通過調(diào)用者調(diào)用接受者執(zhí)行命令斗搞,順序:調(diào)用者→接受者→命令。
關(guān)鍵代碼:
定義三個角色:
1慷妙、received 真正的命令執(zhí)行對象
2僻焚、Command
3、invoker 使用命令對象的入口
應(yīng)用實(shí)例:
struts 1 中的 action 核心控制器 ActionServlet 只有一個膝擂,相當(dāng)于 Invoker虑啤,而模型層的類會隨著不同的應(yīng)用有不同的模型類,相當(dāng)于具體的 Command架馋。
優(yōu)點(diǎn):
1狞山、降低了系統(tǒng)耦合度。
2绩蜻、新的命令可以很容易添加到系統(tǒng)中去铣墨。
缺點(diǎn):
使用命令模式可能會導(dǎo)致某些系統(tǒng)有過多的具體命令類。
使用場景:
認(rèn)為是命令的地方都可以使用命令模式办绝,比如:
1伊约、GUI 中每一個按鈕都是一條命令。
2孕蝉、模擬 CMD屡律。
注意事項:
系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(fù)(Redo)操作,也可以考慮使用命令模式降淮,見命令模式的擴(kuò)展超埋。
19.備忘錄模式
備忘錄模式(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)用實(shí)例:
1谴垫、后悔藥常侣。
2、打游戲時的存檔弹渔。
3、Windows 里的 ctri + z溯祸。
4肢专、IE 中的后退。
5焦辅、數(shù)據(jù)庫的事務(wù)管理博杖。
優(yōu)點(diǎn):
1、給用戶提供了一種可以恢復(fù)狀態(tài)的機(jī)制筷登,可以使用戶能夠比較方便地回到某個歷史的狀態(tài)剃根。
2、實(shí)現(xiàn)了信息的封裝前方,使得用戶不需要關(guān)心狀態(tài)的保存細(xì)節(jié)狈醉。
缺點(diǎn):
消耗資源。如果類的成員變量過多惠险,勢必會占用比較大的資源苗傅,而且每一次保存都會消耗一定的內(nèi)存。
使用場景:
1班巩、需要保存/恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場景渣慕。 2、提供一個可回滾的操作。
注意事項:
1逊桦、為了符合迪米特原則眨猎,還要增加一個管理備忘錄的類。
2强经、為了節(jié)約內(nèi)存睡陪,可使用原型模式+備忘錄模式。
20.狀態(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)模式的實(shí)現(xiàn)類的方法,一般返回值不铆,或者是改變實(shí)例變量的值蝌焚。也就是說,狀態(tài)模式一般和對象的狀態(tài)有關(guān)誓斥。實(shí)現(xiàn)類的方法有不同的功能只洒,覆蓋接口中的方法。狀態(tài)模式和命令模式一樣劳坑,也可以用于消除 if...else 等條件選擇語句毕谴。
應(yīng)用實(shí)例:
1、打籃球的時候運(yùn)動員可以有正常狀態(tài)距芬、不正常狀態(tài)和超常狀態(tài)涝开。
2、曾侯乙編鐘中蔑穴,'鐘是抽象接口','鐘A'等是具體狀態(tài)忠寻,'曾侯乙編鐘'是具體環(huán)境(Context)。
優(yōu)點(diǎn):
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ù)。
缺點(diǎn):
1山叮、狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)怜械。
2番宁、狀態(tài)模式的結(jié)構(gòu)與實(shí)現(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 個剑刑。
21.訪問者模式
在訪問者模式(Visitor Pattern)中,我們使用了一個訪問者類双肤,它改變了元素類的執(zhí)行算法施掏。通過這種方式,元素的執(zhí)行算法可以隨著訪問者改變而改變茅糜。這種類型的設(shè)計模式屬于行為型模式七芭。根據(jù)模式,元素對象已接受訪問者對象蔑赘,這樣訪問者對象就可以處理元素對象上的操作狸驳。
介紹
意圖:
主要將數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作分離预明。
主要解決:
穩(wěn)定的數(shù)據(jù)結(jié)構(gòu)和易變的操作耦合問題。
何時使用:
需要對一個對象結(jié)構(gòu)中的對象進(jìn)行很多不同的并且不相關(guān)的操作耙箍,而需要避免讓這些操作"污染"這些對象的類撰糠,使用訪問者模式將這些封裝到類中。
如何解決:
在被訪問的類里面加一個對外提供接待訪問者的接口辩昆。
關(guān)鍵代碼:
在數(shù)據(jù)基礎(chǔ)類里面有一個方法接受訪問者阅酪,將自身引用傳入訪問者。
應(yīng)用實(shí)例:
您在朋友家做客汁针,您是訪問者术辐,朋友接受您的訪問,您通過朋友的描述施无,然后對朋友的描述做出一個判斷辉词,這就是訪問者模式。
優(yōu)點(diǎn):
1帆精、符合單一職責(zé)原則较屿。
2、優(yōu)秀的擴(kuò)展性卓练。
3隘蝎、靈活性。
缺點(diǎn):
1襟企、具體元素對訪問者公布細(xì)節(jié)嘱么,違反了迪米特原則。
2顽悼、具體元素變更比較困難曼振。
3、違反了依賴倒置原則蔚龙,依賴了具體類冰评,沒有依賴抽象。
使用場景:
1木羹、對象結(jié)構(gòu)中對象對應(yīng)的類很少改變甲雅,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作。
2坑填、需要對一個對象結(jié)構(gòu)中的對象進(jìn)行很多不同的并且不相關(guān)的操作抛人,而需要避免讓這些操作"污染"這些對象的類,也不希望在增加新操作時修改這些類脐瑰。
注意事項:
訪問者可以對功能進(jìn)行統(tǒng)一妖枚,可以做報表、UI苍在、攔截器與過濾器绝页。
22.中介者模式
中介者模式(Mediator Pattern)是用來降低多個對象和類之間的通信復(fù)雜性荠商。這種模式提供了一個中介類,該類通常處理不同類之間的通信抒寂,并支持松耦合结啼,使代碼易于維護(hù)。中介者模式屬于行為型模式屈芜。
介紹
意圖:
用一個中介對象來封裝一系列的對象交互郊愧,中介者使各對象不需要顯式地相互引用,從而使其耦合松散井佑,而且可以獨(dú)立地改變它們之間的交互属铁。
主要解決:
對象與對象之間存在大量的關(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 之間的通信封裝到一個類中單獨(dú)處理拼卵。
應(yīng)用實(shí)例:
1、中國加入 WTO 之前是各個國家相互貿(mào)易蛮艰,結(jié)構(gòu)復(fù)雜腋腮,現(xiàn)在是各個國家通過 WTO 來互相貿(mào)易。
2壤蚜、機(jī)場調(diào)度系統(tǒng)即寡。
3、MVC 框架袜刷,其中C(控制器)就是 M(模型)和 V(視圖)的中介者聪富。
優(yōu)點(diǎn):
1、降低了類的復(fù)雜度著蟹,將一對多轉(zhuǎn)化成了一對一善涨。
2、各個類之間的解耦草则。
3、符合迪米特原則蟹漓。
缺點(diǎn):
中介者會龐大炕横,變得復(fù)雜難以維護(hù)。
使用場景:
1葡粒、系統(tǒng)中對象之間存在比較復(fù)雜的引用關(guān)系份殿,導(dǎo)致它們之間的依賴關(guān)系結(jié)構(gòu)混亂而且難以復(fù)用該對象膜钓。
2、想通過一個中間類來封裝多個類中的行為卿嘲,而又不想生成太多的子類颂斜。
注意事項:
不應(yīng)當(dāng)在職責(zé)混亂的時候使用。
23.解釋器模式
解釋器模式(Interpreter Pattern)提供了評估語言的語法或表達(dá)式的方式拾枣,它屬于行為型模式沃疮。這種模式實(shí)現(xiàn)了一個表達(dá)式接口,該接口解釋一個特定的上下文梅肤。這種模式被用在 SQL 解析司蔬、符號處理引擎等。
介紹
意圖:
給定一個語言姨蝴,定義它的文法表示俊啼,并定義一個解釋器,這個解釋器使用該標(biāo)識來解釋語言中的句子左医。
主要解決:
對于一些固定文法構(gòu)建一個解釋句子的解釋器授帕。
何時使用:
如果一種特定類型的問題發(fā)生的頻率足夠高,那么可能就值得將該問題的各個實(shí)例表述為一個簡單語言中的句子浮梢。這樣就可以構(gòu)建一個解釋器跛十,該解釋器通過解釋這些句子來解決該問題。
如何解決:
構(gòu)件語法樹黔寇,定義終結(jié)符與非終結(jié)符偶器。
關(guān)鍵代碼:
構(gòu)件環(huán)境類,包含解釋器之外的一些全局信息缝裤,一般是 HashMap屏轰。
應(yīng)用實(shí)例:
編譯器、運(yùn)算表達(dá)式計算憋飞。
優(yōu)點(diǎn):
1霎苗、可擴(kuò)展性比較好,靈活榛做。
2唁盏、增加了新的解釋表達(dá)式的方式。
3检眯、易于實(shí)現(xiàn)簡單文法厘擂。
缺點(diǎn):
1、可利用場景比較少锰瘸。
2刽严、對于復(fù)雜的文法比較難維護(hù)。
3避凝、解釋器模式會引起類膨脹舞萄。
4眨补、解釋器模式采用遞歸調(diào)用方法。
使用場景:
1倒脓、可以將一個需要解釋執(zhí)行的語言中的句子表示為一個抽象語法樹撑螺。
2、一些重復(fù)出現(xiàn)的問題可以用一種簡單的語言來進(jìn)行表達(dá)崎弃。
3甘晤、一個簡單語法需要解釋的場景。
注意事項:
可利用場景比較少吊履,JAVA 中如果碰到可以用 expression4J 代替安皱。