博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
工廠模式(Factory Pattern)
工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的介面來指向新創建的對象。
意圖:定義一個創建對象的介面,讓其子類自己決定實例化哪一個工廠類,工廠模式使其創建過程延遲到子類進行。
主要解決:主要解決介面選擇的問題。
何時使用:我們明確地計劃不同條件下創建不同實例時。
如何解決:讓其子類實現工廠介面,返回的也是一個抽象的產品。
關鍵代碼:創建過程在其子類執行。
應用實例:
1、您需要一輛汽車,可以直接從工廠裡面提貨,而不用去管這輛汽車是怎麼做出來的,以及這個汽車裡面的具體實現。
2、Hibernate 換資料庫只需換方言和驅動就可以。
優點:
1、一個調用者想創建一個對象,只要知道其名稱就可以了。
2、擴展性高,如果想增加一個產品,只要擴展一個工廠類就可以。
3、屏蔽產品的具體實現,調用者只關心產品的介面。
缺點:每次增加一個產品時,都需要增加一個具體類和對象實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加了系統具體類的依賴。這並不是什麼好事。
使用場景:
1、日誌記錄器:記錄可能記錄到本地硬碟、系統事件、遠程伺服器等,用戶可以選擇記錄日誌到什麼地方。
2、資料庫訪問,當用戶不知道最後系統採用哪一類資料庫,以及資料庫可能有變化時。
3、設計一個連接伺服器的框架,需要三個協議,"POP3"、"IMAP"、"HTTP",可以把這三個作為產品類,共同實現一個介面。
註意事項:作為一種創建類模式,在任何需要生成複雜對象的地方,都可以使用工廠方法模式。有一點需要註意的地方就是複雜對象適合使用工廠模式,而簡單對象,特別是只需要通過 new 就可以完成創建的對象,無需使用工廠模式。如果使用工廠模式,就需要引入一個工廠類,會增加系統的複雜度。
抽象工廠模式(Abstract Factory Pattern)
抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠創建其他工廠。該超級工廠又稱為其他工廠的工廠。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
在抽象工廠模式中,介面是負責創建一個相關對象的工廠,不需要顯式指定它們的類。每個生成的工廠都能按照工廠模式提供對象。
意圖:提供一個創建一系列相關或相互依賴對象的介面,而無需指定它們具體的類。
主要解決:主要解決介面選擇的問題。
何時使用:系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
如何解決:在一個產品族裡面,定義多個產品。
關鍵代碼:在一個工廠里聚合多個同類產品。
應用實例:工作了,為了參加一些聚會,肯定有兩套或多套衣服吧,比如說有商務裝(成套,一系列具體產品)、時尚裝(成套,一系列具體產品),甚至對於一個家庭來說,可能有商務女裝、商務男裝、時尚女裝、時尚男裝,這些也都是成套的,即一系列具體產品。假設一種情況(現實中是不存在的,要不然,沒法進入共產主義了,但有利於說明抽象工廠模式),在您的家中,某一個衣櫃(具體工廠)只能存放某一種這樣的衣服(成套,一系列具體產品),每次拿這種成套的衣服時也自然要從這個衣櫃中取出了。用 OOP 的思想去理解,所有的衣櫃(具體工廠)都是衣櫃類的(抽象工廠)某一個,而每一件成套的衣服又包括具體的上衣(某一具體產品),褲子(某一具體產品),這些具體的上衣其實也都是上衣(抽象產品),具體的褲子也都是褲子(另一個抽象產品)。
優點:當一個產品族中的多個對象被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的對象。
缺點:產品族擴展非常困難,要增加一個系列的某一產品,既要在抽象的 Creator 裡加代碼,又要在具體的裡面加代碼。
使用場景:
1、QQ 換皮膚,一整套一起換。
2、生成不同操作系統的程式。
註意事項:產品族難擴展,產品等級易擴展。
單例模式(Singleton Pattern)
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
註意:
- 1、單例類只能有一個實例。
- 2、單例類必須自己創建自己的唯一實例。
- 3、單例類必須給所有其他對象提供這一實例。
意圖:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
主要解決:一個全局使用的類頻繁地創建與銷毀。
何時使用:當您想控制實例數目,節省系統資源的時候。
如何解決:判斷系統是否已經有這個單例,如果有則返回,如果沒有則創建。
關鍵代碼:構造函數是私有的。
應用實例:
- 1、一個班級只有一個班主任。
- 2、Windows 是多進程多線程的,在操作一個文件的時候,就不可避免地出現多個進程或線程同時操作一個文件的現象,所以所有文件的處理必須通過唯一的實例來進行。
- 3、一些設備管理器常常設計為單例模式,比如一個電腦有兩台印表機,在輸出的時候就要處理不能兩台印表機列印同一個文件。
優點:
- 1、在記憶體里只有一個實例,減少了記憶體的開銷,尤其是頻繁的創建和銷毀實例(比如管理學院首頁頁面緩存)。
- 2、避免對資源的多重占用(比如寫文件操作)。
缺點:沒有介面,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。
使用場景:
- 1、要求生產唯一序列號。
- 2、WEB 中的計數器,不用每次刷新都在資料庫裡加一次,用單例先緩存起來。
- 3、創建的一個對象需要消耗的資源過多,比如 I/O 與資料庫的連接等。
註意事項:getInstance() 方法中需要使用同步鎖 synchronized (Singleton.class) 防止多線程同時進入造成 instance 被多次實例化。
建造者模式(Builder Pattern)
建造者模式(Builder Pattern)使用多個簡單的對象一步一步構建成一個複雜的對象。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
一個 Builder 類會一步一步構造最終的對象。該 Builder 類是獨立於其他對象的。
意圖:將一個複雜的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。
主要解決:主要解決在軟體系統中,有時候面臨著"一個複雜對象"的創建工作,其通常由各個部分的子對象用一定的演算法構成;由於需求的變化,這個複雜對象的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的演算法卻相對穩定。
何時使用:一些基本部件不會變,而其組合經常變化的時候。
如何解決:將變與不變分離開。
關鍵代碼:建造者:創建和提供實例,導演:管理建造出來的實例的依賴關係。
應用實例:
1、去肯德基,漢堡、可樂、薯條、炸雞翅等是不變的,而其組合是經常變化的,生成出所謂的"套餐"。
2、JAVA 中的 StringBuilder。
優點:
1、建造者獨立,易擴展。
2、便於控制細節風險。
缺點:
1、產品必須有共同點,範圍有限制。
2、如內部變化複雜,會有很多的建造類。
使用場景:
1、需要生成的對象具有複雜的內部結構。
2、需要生成的對象內部屬性本身相互依賴。
註意事項:與工廠模式的區別是:建造者模式更加關註與零件裝配的順序。
原型模式(Prototype Pattern)
原型模式(Prototype Pattern)是用於創建重覆的對象,同時又能保證性能。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
這種模式是實現了一個原型介面,該介面用於創建當前對象的克隆。當直接創建對象的代價比較大時,則採用這種模式。例如,一個對象需要在一個高代價的資料庫操作之後被創建。我們可以緩存該對象,在下一個請求時返回它的克隆,在需要的時候更新資料庫,以此來減少資料庫調用。
意圖:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。
主要解決:在運行期建立和刪除原型。
何時使用:
1、當一個系統應該獨立於它的產品創建,構成和表示時。
2、當要實例化的類是在運行時刻指定時,例如,通過動態裝載。
3、為了避免創建一個與產品類層次平行的工廠類層次時。
4、當一個類的實例只能有幾個不同狀態組合中的一種時。建立相應數目的原型並克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。
如何解決:利用已有的一個原型對象,快速地生成和原型對象一樣的實例。
關鍵代碼:
1、實現克隆操作,在 JAVA 繼承 Cloneable,重寫 clone(),在 .NET 中可以使用 Object 類的 MemberwiseClone() 方法來實現對象的淺拷貝或通過序列化的方式來實現深拷貝。
2、原型模式同樣用於隔離類對象的使用者和具體類型(易變類)之間的耦合關係,它同樣要求這些"易變類"擁有穩定的介面。
應用實例:
1、細胞分裂。
2、JAVA 中的 Object clone() 方法。
優點:
1、性能提高。
2、逃避構造函數的約束。
缺點:
1、配備克隆方法需要對類的功能進行通盤考慮,這對於全新的類不是很難,但對於已有的類不一定很容易,特別當一個類引用不支持串列化的間接對象,或者引用含有迴圈結構的時候。
2、必須實現 Cloneable 介面。
使用場景:
1、資源優化場景。
2、類初始化需要消化非常多的資源,這個資源包括數據、硬體資源等。
3、性能和安全要求的場景。
4、通過 new 產生一個對象需要非常繁瑣的數據準備或訪問許可權,則可以使用原型模式。
5、一個對象多個修改者的場景。
6、一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用。
7、在實際項目中,原型模式很少單獨出現,一般是和工廠方法模式一起出現,通過 clone 的方法創建一個對象,然後由工廠方法提供給調用者。原型模式已經與 Java 融為渾然一體,大家可以隨手拿來使用。
註意事項:與通過對一個類進行實例化來構造新對象不同的是,原型模式是通過拷貝一個現有對象生成新對象的。淺拷貝實現 Cloneable,重寫,深拷貝是通過實現 Serializable 讀取二進位流。
適配器模式(Adapter Pattern)
適配器模式(Adapter Pattern)是作為兩個不相容的介面之間的橋梁。這種類型的設計模式屬於結構型模式,它結合了兩個獨立介面的功能。
這種模式涉及到一個單一的類,該類負責加入獨立的或不相容的介面功能。舉個真實的例子,讀卡器是作為記憶體卡和筆記本之間的適配器。您將記憶體卡插入讀卡器,再將讀卡器插入筆記本,這樣就可以通過筆記本來讀取記憶體卡。
我們通過下麵的實例來演示適配器模式的使用。其中,音頻播放器設備只能播放 mp3 文件,通過使用一個更高級的音頻播放器來播放 vlc 和 mp4 文件。
意圖:將一個類的介面轉換成客戶希望的另外一個介面。適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
主要解決:主要解決在軟體系統中,常常要將一些"現存的對象"放到新的環境中,而新環境要求的介面是現對象不能滿足的。
何時使用:
1、系統需要使用現有的類,而此類的介面不符合系統的需要。
2、想要建立一個可以重覆使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作,這些源類不一定有一致的介面。
3、通過介面轉換,將一個類插入另一個類系中。(比如老虎和飛禽,現在多了一個飛虎,在不增加實體的需求下,增加一個適配器,在裡面包容一個虎對象,實現飛的介面。)
如何解決:繼承或依賴(推薦)。
關鍵代碼:適配器繼承或依賴已有的對象,實現想要的目標介面。
應用實例:
1、美國電器 110V,中國 220V,就要有一個適配器將 110V 轉化為 220V。
2、JAVA JDK 1.1 提供了 Enumeration 介面,而在 1.2 中提供了 Iterator 介面,想要使用 1.2 的 JDK,則要將以前系統的 Enumeration 介面轉化為 Iterator 介面,這時就需要適配器模式。
3、在 LINUX 上運行 WINDOWS 程式。
4、JAVA 中的 jdbc。
優點:
1、可以讓任何兩個沒有關聯的類一起運行。
2、提高了類的復用。
3、增加了類的透明度。
4、靈活性好。
缺點:
1、過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 介面,其實內部被適配成了 B 介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
2.由於 JAVA 至多繼承一個類,所以至多只能適配一個適配者類,而且目標類必須是抽象類。
使用場景:有動機地修改一個正常運行的系統的介面,這時應該考慮使用適配器模式。
註意事項:適配器不是在詳細設計時添加的,而是解決正在服役的項目的問題。
橋接模式(Bridge Pattern)
橋接(Bridge)是用於把抽象化與實現化解耦,使得二者可以獨立變化。這種類型的設計模式屬於結構型模式,它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。
這種模式涉及到一個作為橋接的介面,使得實體類的功能獨立於介面實現類。這兩種類型的類可被結構化改變而互不影響。
我們通過下麵的實例來演示橋接模式(Bridge Pattern)的用法。其中,可以使用相同的抽象類方法但是不同的橋接實現類,來畫出不同顏色的圓。
意圖:將抽象部分與實現部分分離,使它們都可以獨立的變化。
主要解決:在有多種可能會變化的情況下,用繼承會造成類爆炸問題,擴展起來不靈活。
何時使用:實現系統可能有多個角度分類,每一種角度都可能變化。
如何解決:把這種多角度分類分離出來,讓它們獨立變化,減少它們之間耦合。
關鍵代碼:抽象類依賴實現類。
應用實例:
1、豬八戒從天蓬元帥轉世投胎到豬,轉世投胎的機制將塵世劃分為兩個等級,即:靈魂和肉體,前者相當於抽象化,後者相當於實現化。生靈通過功能的委派,調用肉體對象的功能,使得生靈可以動態地選擇。
2、牆上的開關,可以看到的開關是抽象的,不用管裡面具體怎麼實現的。
優點:
1、抽象和實現的分離。
2、優秀的擴展能力。
3、實現細節對客戶透明。
缺點:橋接模式的引入會增加系統的理解與設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計與編程。
使用場景:
1、如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯繫,通過橋接模式可以使它們在抽象層建立一個關聯關係。
2、對於那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。
3、一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。
註意事項:對於兩個獨立變化的維度,使用橋接模式再適合不過了。
過濾器模式(Filter、Criteria Pattern)
過濾器模式(Filter Pattern)或標準模式(Criteria Pattern)是一種設計模式,這種模式允許開發人員使用不同的標準來過濾一組對象,通過邏輯運算以解耦的方式把它們連接起來。這種類型的設計模式屬於結構型模式,它結合多個標準來獲得單一標準。
組合模式(Composite Pattern)
組合模式(Composite Pattern),又叫部分整體模式,是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬於結構型模式,它創建了對象組的樹形結構。
這種模式創建了一個包含自己對象組的類。該類提供了修改相同對象組的方式。
我們通過下麵的實例來演示組合模式的用法。實例演示了一個組織中員工的層次結構。
意圖:將對象組合成樹形結構以表示"部分-整體"的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。
主要解決:它在我們樹型結構的問題中,模糊了簡單元素和複雜元素的概念,客戶程式可以像處理簡單元素一樣來處理複雜元素,從而使得客戶程式與複雜元素的內部結構解耦。
何時使用:
1、您想表示對象的部分-整體層次結構(樹形結構)。
2、您希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
如何解決:樹枝和葉子實現統一介面,樹枝內部組合該介面。
關鍵代碼:樹枝內部組合該介面,並且含有內部屬性 List,裡面放 Component。
應用實例:
1、算術表達式包括操作數、操作符和另一個操作數,其中,另一個操作數也可以是操作數、操作符和另一個操作數。
2、在 JAVA AWT 和 SWING 中,對於 Button 和 Checkbox 是樹葉,Container 是樹枝。
優點:
1、高層模塊調用簡單。
2、節點自由增加。
缺點:在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是介面,違反了依賴倒置原則。
使用場景:部分、整體場景,如樹形菜單,文件、文件夾的管理。
註意事項:定義時為具體類。
裝飾器模式(Decorator Pattern)
裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是作為現有的類的一個包裝。
這種模式創建了一個裝飾類,用來包裝原有的類,併在保持類方法簽名完整性的前提下,提供了額外的功能。
我們通過下麵的實例來演示裝飾器模式的用法。其中,我們將把一個形狀裝飾上不同的顏色,同時又不改變形狀類。
意圖:動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾器模式相比生成子類更為靈活。
主要解決:一般的,我們為了擴展一個類經常使用繼承方式實現,由於繼承為類引入靜態特征,並且隨著擴展功能的增多,子類會很膨脹。
何時使用:在不想增加很多子類的情況下擴展類。
如何解決:將具體功能職責劃分,同時繼承裝飾者模式。
關鍵代碼:
1、Component 類充當抽象角色,不應該具體實現。
2、修飾類引用和繼承 Component 類,具體擴展類重寫父類方法。
應用實例:
1、孫悟空有 72 變,當他變成"廟宇"後,他的根本還是一隻猴子,但是他又有了廟宇的功能。
2、不論一幅畫有沒有畫框都可以掛在牆上,但是通常都是有畫框的,並且實際上是畫框被掛在牆上。在掛在牆上之前,畫可以被蒙上玻璃,裝到框子里;這時畫、玻璃和畫框形成了一個物體。
優點:裝飾類和被裝飾類可以獨立發展,不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動態擴展一個實現類的功能。
缺點:多層裝飾比較複雜。
使用場景:
1、擴展一個類的功能。
2、動態增加功能,動態撤銷。
註意事項:可代替繼承。
外觀模式(Facade Pattern)
外觀模式(Facade Pattern)隱藏系統的複雜性,並向客戶端提供了一個客戶端可以訪問系統的介面。這種類型的設計模式屬於結構型模式,它向現有的系統添加一個介面,來隱藏系統的複雜性。
這種模式涉及到一個單一的類,該類提供了客戶端請求的簡化方法和對現有系統類方法的委托調用。
意圖:為子系統中的一組介面提供一個一致的界面,外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
主要解決:降低訪問複雜系統的內部子系統時的複雜度,簡化客戶端之間的介面。
何時使用:
1、客戶端不需要知道系統內部的複雜聯繫,整個系統只需提供一個"接待員"即可。
2、定義系統的入口。
如何解決:客戶端不與系統耦合,外觀類與系統耦合。
關鍵代碼:在客戶端和複雜系統之間再加一層,這一層將調用順序、依賴關係等處理好。
應用實例:
1、去醫院看病,可能要去掛號、門診、劃價、取藥,讓患者或患者家屬覺得很複雜,如果有提供接待人員,只讓接待人員來處理,就很方便。
2、JAVA 的三層開發模式。
優點:
1、減少系統相互依賴。
2、提高靈活性。
3、提高了安全性。
缺點:不符合開閉原則,如果要改東西很麻煩,繼承重寫都不合適。
使用場景:
1、為複雜的模塊或子系統提供外界訪問的模塊。
2、子系統相對獨立。
3、預防低水平人員帶來的風險。
註意事項:在層次化結構中,可以使用外觀模式定義系統中每一層的入口。
享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern)主要用於減少創建對象的數量,以減少記憶體占用和提高性能。這種類型的設計模式屬於結構型模式,它提供了減少對象數量從而改善應用所需的對象結構的方式。
享元模式嘗試重用現有的同類對象,如果未找到匹配的對象,則創建新對象。我們將通過創建 5 個對象來畫出 20 個分佈於不同位置的圓來演示這種模式。由於只有 5 種可用的顏色,所以 color 屬性被用來檢查現有的 Circle 對象。
意圖:運用共用技術有效地支持大量細粒度的對象。
主要解決:在有大量對象時,有可能會造成記憶體溢出,我們把其中共同的部分抽象出來,如果有相同的業務請求,直接返回在記憶體中已有的對象,避免重新創建。
何時使用:
1、系統中有大量對象。
2、這些對象消耗大量記憶體。
3、這些對象的狀態大部分可以外部化。
4、這些對象可以按照內蘊狀態分為很多組,當把外蘊對象從對象中剔除出來時,每一組對象都可以用一個對象來代替。
5、系統不依賴於這些對象身份,這些對象是不可分辨的。
如何解決:用唯一標識碼判斷,如果在記憶體中有,則返回這個唯一標識碼所標識的對象。
關鍵代碼:用 HashMap 存儲這些對象。
應用實例:
1、JAVA 中的 String,如果有則返回,如果沒有則創建一個字元串保存在字元串緩存池裡面。
2、資料庫的數據池。
優點:大大減少對象的創建,降低系統的記憶體,使效率提高。
缺點:提高了系統的複雜度,需要分離出外部狀態和內部狀態,而且外部狀態具有固有化的性質,不應該隨著內部狀態的變化而變化,否則會造成系統的混亂。
使用場景:
1、系統有大量相似對象。
2、需要緩衝池的場景。
註意事項:
1、註意劃分外部狀態和內部狀態,否則可能會引起線程安全問題。
2、這些類必須有一個工廠對象加以控制。
代理模式(Proxy Pattern)
在代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設計模式屬於結構型模式。
在代理模式中,我們創建具有現有對象的對象,以便向外界提供功能介面。
意圖:為其他對象提供一種代理以控制對這個對象的訪問。
主要解決:在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象由於某些原因(比如對象創建開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。
何時使用:想在訪問一個類時做一些控制。
如何解決:增加中間層。
關鍵代碼:實現與被代理類組合。
應用實例:
1、Windows 裡面的快捷方式。
2、豬八戒去找高翠蘭結果是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現了這個介面,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,所以說孫悟空是高翠蘭代理類。
3、買火車票不一定在火車站買,也可以去代售點。
4、一張支票或銀行存單是賬戶中資金的代理。支票在市場交易中用來代替現金,並提供對簽發人賬號上資金的控制。
5、spring aop。
優點:
1、職責清晰。
2、高擴展性。
3、智能化。
缺點:
1、由於在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢。
2、實現代理模式需要額外的工作,有些代理模式的實現非常複雜。
使用場景:按職責來劃分,通常有以下使用場景:
1、遠程代理。
2、虛擬代理。
3、Copy-on-Write 代理。
4、保護(Protect or Access)代理。
5、Cache代理。
6、防火牆(Firewall)代理。
7、同步化(Synchronization)代理。
8、智能引用(Smart Reference)代理。
註意事項:
1、和適配器模式的區別:適配器模式主要改變所考慮對象的介面,而代理模式不能改變所代理類的介面。
2、和裝飾器模式的區別:裝飾器模式為了增強功能,而代理模式是為了加以控制。
責任鏈模式(Chain of Responsibility Pattern)
顧名思義,責任鏈模式(Chain of Responsibility Pattern)為請求創建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發送者和接收者進行解耦。這種類型的設計模式屬於行為型模式。
在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
意圖:避免請求發送者與接收者耦合在一起,讓多個對象都有可能接收請求,將這些對象連接成一條鏈,並且沿著這條鏈傳遞請求,直到有對象處理它為止。
主要解決:職責鏈上的處理者負責處理請求,客戶只需要將請求發送到職責鏈上即可,無須關心請求的處理細節和請求的傳遞,所以職責鏈將請求的發送者和請求的處理者解耦了。
何時使用:在處理消息的時候以過濾很多道。
如何解決:攔截的類都實現統一介面。
關鍵代碼:Handler 裡面聚合它自己,在 HandlerRequest 里判斷是否合適,如果沒達到條件則向下傳遞,向誰傳遞之前 set 進去。
應用實例:
1、紅樓夢中的"擊鼓傳花"。
2、JS 中的事件冒泡。
3、JAVA WEB 中 Apache Tomcat 對 Encoding 的處理,Struts2 的攔截器,jsp servlet 的 Filter。
優點:
1、降低耦合度。它將請求的發送者和接收者解耦。
2、簡化了對象。使得對象不需要知道鏈的結構。
3、增強給對象指派職責的靈活性。通過改變鏈內的成員或者調動它們的次序,允許動態地新增或者刪除責任。
4、增加新的請求處理類很方便。
缺點:
1、不能保證請求一定被接收。
2、系統性能將受到一定影響,而且在進行代碼調試時不太方便,可能會造成迴圈調用。
3、可能不容易觀察運行時的特征,有礙於除錯。
使用場景:
1、有多個對象可以處理同一個請求,具體哪個對象處理該請求由運行時刻自動確定。
2、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
3、可動態指定一組對象處理請求。
註意事項:在 JAVA WEB 中遇到很多應用。
命令模式(Command Pattern)
命令模式(Command Pattern)是一種數據驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在對象中,並傳給調用對象。調用對象尋找可以處理該命令的合適的對象,並把該命令傳給相應的對象,該對象執行命令。
意圖:將一個請求封裝成一個對象,從而使您可以用不同的請求對客戶進行參數化。
主要解決:在軟體系統中,行為請求者與行為實現者通常是一種緊耦合的關係,但某些場合,比如需要對行為進行記錄、撤銷或重做、事務等處理時,這種無法抵禦變化的緊耦合的設計就不太合適。
何時使用:在某些場合,比如要對行為進行"記錄、撤銷/重做、事務"等處理,這種無法抵禦變化的緊耦合是不合適的。在這種情況下,如何將"行為請求者"與"行為實現者"解耦?將一組行為抽象為對象,可以實現二者之間的松耦合。
如何解決:通過調用者調用接受者執行命令,順序:調用者→命令→接受者。
關鍵代碼:定義三個角色:
1、received 真正的命令執行對象
2、Command
3、invoker 使用命令對象的入口
應用實例:struts 1 中的 action 核心控制器 ActionServlet 只有一個,相當於 Invoker,而模型層的類會隨著不同的應用有不同的模型類,相當於具體的 Command。
優點:
1、降低了系統耦合度。
2、新的命令可以很容易添加到系統中去。
缺點:使用命令模式可能會導致某些系統有過多的具體命令類。
使用場景:認為是命令的地方都可以使用命令模式,比如: 1、GUI 中每一個按鈕都是一條命令。 2、模擬 CMD。
註意事項:系統需要支持命令的撤銷(Undo)操作和恢復(Redo)操作,也可以考慮使用命令模式,見命令模式的擴展。
命令模式結構示意圖:
解釋器模式(Interpreter Pattern)
解釋器模式(Interpreter Pattern)提供了評估語言的語法或表達式的方式,它屬於行為型模式。這種模式實現了一個表達式介面,該介面解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。
意圖:給定一個語言,定義它的文法表示,並定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。
主要解決:對於一些固定文法構建一個解釋句子的解釋器。
何時使用:如果一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述為一個簡單語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。
如何解決:構建語法樹,定義終結符與非終結符。
關鍵代碼:構建環境類,包含解釋器之外的一些全局信息,一般是 HashMap。
應用實例:編譯器、運算表達式計算。
優點:
1、可擴展性比較好,靈活。
2、增加了新的解釋表達式的方式。
3、易於實現簡單文法。
缺點:
1、可利用場景比較少。
2、對於複雜的文法比較難維護。
3、解釋器模式會引起類膨脹。
4、解釋器模式採用遞歸調用方法。
使用場景:
1、可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹。
2、一些重覆出現的問題可以用一種簡單的語言來進行表達。
3、一個簡單語法需要解釋的場景。
註意事項:可利用場景比較少,JAVA 中如果碰到可以用 expression4J 代替。
迭代器模式(Iterator Pattern)
迭代器模式(Iterator Pattern)是 Java 和 .Net 編程環境中非常常用的設計模式。這種模式用於順序訪問集合對象的元素,不需要知道集合對象的底層表示。
迭代器模式屬於行為型模式。
意圖:提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內部表示。
主要解決:不同的方式來遍歷整個整合對象。
何時使用:遍歷一個聚合對象。
如何解決:把在元素之間游走的責任交給迭代器,而不是聚合對象。
關鍵代碼:定義介面:hasNext, next。
應用實例:JAVA 中的 iterator。
優點:
1、它支持以不同的方式遍歷一個聚合對象。
2、迭代器簡化了聚合類。
3、在同一個聚合上可以有多個遍歷。
4、在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有代碼。
缺點:由於迭代器模式將存儲數據和遍曆數據的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性。
使用場景:
1、訪問一個聚合對象的內容而無須暴露它的內部表示。
2、需要為聚合對象提供多種遍歷方式。
3、為遍歷不同的聚合結構提供一個統一的介面。
註意事項:迭代器模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。
中介者模式(Mediator Pattern)
中介者模式(Mediator Pattern)是用來降低多個對象和類之間的通信複雜性。這種模式提供了一個中介類,該類通常處理不同類之間的通信,並支持松耦合,使代碼易於維護。中介者模式屬於行為型模式。
意圖:用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。
主要解決:對象與對象之間存在大量的關聯關係,這樣勢必會導致系統的結構變得很複雜,同時若一個對象發生改變,我們也需要跟蹤與之相關聯的對象,同時做出相應的處理。
何時使用:多個類相互耦合,形成了網狀結構。
如何解決:將上述網狀結構分離為星型結構。
關鍵代碼:對象 Colleague 之間的通信封裝到一個類中單獨處理。
應用實例:
1、中國加入 WTO 之前是各個國家相互貿易,結構複雜,現在是各個國家通過 WTO 來互相貿易。
2、機場調度系統。
3、MVC 框架,其中C(控制器)就是 M(模型)和 V(視圖)的中介者。
優點:
1、降低了類的複雜度,將一對多轉化成了一對一。
2、各個類之間的解耦。
3、符合迪米特原則。
缺點:中介者會龐大,變得複雜難以維護。
使用場景:
1、系統中對象之間存在比較複雜的引用關係,導致它們之間的依賴關係結構混亂而且難以復用該對象。
2、想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。