Java進階篇 設計模式之十四 ----- 總結篇
前言
本篇是講述之前學習設計模式的一個總結篇,其目的是為了對這些設計模式的進行一個提煉總結,能夠通過檢視看此篇就可以理解一些設計模式的核心思想。
設計模式簡介
什麼是設計模式
設計模式是一套被反覆使用的、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。
為什麼使用設計模式
使用設計模式是為了重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。
設計模式型別
設計模式有23種類型。按照主要分類可以分為三大類:
一、建立型模式
這些設計模式提供了一種在建立物件的同時隱藏建立邏輯的方式,而不是使用 new運算子直接例項化物件。這使得程式在判斷針對某個給定例項需要建立哪些物件時更加靈活。
- 單例模式
- 工廠模式
- 抽象工廠模式
- 建造者模式
- 原型模式
二、結構型模式
這些設計模式關注類和物件的組合。繼承的概念被用來組合介面和定義組合物件獲得新功能的方式。
- 介面卡模式
- 橋接模式
- 過濾器模式
- 組合模式
- 裝飾器模式
- 外觀模式
- 享元模式
- 代理模式
三、行為型模式
這些設計模式特別關注物件之間的通訊。
- 責任鏈模式
- 命令模式
- 直譯器模式
- 迭代器模式
- 中介者模式
- 備忘錄模式
- 觀察者模式
- 狀態模式
- 空物件模式
- 策略模式
- 模板模式
- 訪問者模式
設計模式的原則
設計模式的六大原則
- 開閉原則:對擴充套件開放,對修改關閉。
- 里氏代換原則:對開閉原則的補充。任何基類可以出現的地方,子類一定可以出現。LSP 是繼承複用的基石,只有當派生類可以替換掉基類,且軟體單位的功能不受到影響時,基類才能真正被複用,而派生類也能夠在基類的基礎上增加新的行為。
- 依賴倒轉原則:針對介面程式設計,依賴於抽象而不依賴於具體。
- 介面隔離原則:儘量使用多個隔離的介面,為了降低類之間的耦合度。
- 迪米特法則:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模組相對獨立。
- 合成複用原則:儘量使用合成/聚合的方式,而不是使用繼承。
設計模式之間的關係圖:
設計模式總概況:
設計模式相關文章:
- 單例模式
- 工廠方法和抽象工廠模式
- 建造者模式和原型模式
- 介面卡模式和橋接模式
- 外觀模式和裝飾器模式
- 組合模式和過濾器模式
- 享元模式和代理模式
- 責任鏈模式和命令模式
- 直譯器模式和迭代器模式
- 訪問者模式和中介者模式
- 策略模式和模板方法模式
- 觀察者模式和空物件模式
建立型模式
單例模式
單例模式介紹
核心就是保證一個系統中的某個類只有一個例項而且該例項易於外界訪問。
單例模式的使用場景
在程式中比較常用的是資料庫連線池、執行緒池、日誌物件等等。
單例模式使用
單例模式的寫法主要有5種,分別是:
- 餓漢式: 簡單安全, 效率低;
- 飽漢式: 簡單不安全, 效率高 ;
- 靜態內部類: 安全, 效率高;
- 雙重鎖檢查: 複雜安全, 效率高;
- 列舉單例:簡單安全, 效率高;
單例模式示例圖
單例模式總結
- 構造方法私有化(private);
- 定義一個私有(private)靜態(static)例項化物件;
- 對外提供一個公共(public)靜態(static)的方法得到該例項;
工廠模式
工廠模式主要有三種,簡單工廠模式、工廠方法模式和抽象工廠模式。但是一般的情況下我們主要用到的是工廠方法模式和抽象工廠模式。
工廠方法模式介紹
其核心是定義一個建立物件的介面,讓其子類自己決定例項化哪一個工廠類,工廠模式使其建立過程延遲到子類進行。
工廠方法模式使用場景
比如生活中的汽車製造,大名鼎鼎的hibernate框架在選擇資料庫方言這塊。
工廠方法模式示例圖
抽象工廠模式介紹
主要核心是提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。
抽象工廠模式使用場景
比如生活中的服裝製造廠,可以單獨製造衣服、褲子、襪子等等,也可以生產一套服裝。
抽象工廠模式示例圖
建造者模式
建造者模式介紹
使用多個簡單的物件一步一步構建成一個複雜的物件。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
簡單的來說就是將一個複雜的東西抽離出來,對外提供一個簡單的呼叫,可以在同樣的構建過程建立不同的表示。和工廠模式很相似,不過相比而言更加註重元件的裝配。
建造者模式使用場景
適用一些基本元件不便,但是組合經常變化的時候。比如超市促銷的大禮包。
建造者模式角色
Builder:指定一個抽象的介面,規定該產品所需實現部件的建立,並不涉及具體的物件部件的建立。
ConcreteBuilder:需實現Builder介面,並且針對不同的邏輯,進行不同方法的建立,最終提供該產品的例項。
Director:用來建立複雜物件的部分,對該部分進行完整的建立或者按照一定的規則進行建立。
Product:示被構造的複雜物件。
建造者模式優缺點
優點:
- 建造者獨立,易擴充套件。
- 便於控制細節風險。
缺點
- 內部結構複雜,不易於理解。
- 產品直接需要有共同點,範圍有控制。
建造者模式示例圖
原型模式
原型模式介紹
用於建立重複的物件,同時又能保證效能。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。核心是克隆。
原型模式使用場景
- 類初始化的時候需要消耗大量資源的時候;
- 獲取資料庫連線繁瑣的時候;
- 一個物件,有很多個修改者的時候;
原型模式優缺點
優點:
1.可以提升效能;
缺點:
1.因為必須實現Cloneable 介面,所以用起來可能不太方便。
原型模式示例圖
結構型模式
介面卡模式
介面卡模式介紹
介面卡模式是作為兩個不相容的介面之間的橋樑。這種型別的設計模式屬於結構型模式,它結合了兩個獨立介面的功能。簡單的來說就是通過某個介面將不相容的兩個類進行相容,俗稱轉換器。
介面卡模式使用
介面卡模式主要有兩種型別,一種是類介面卡模式,主要通過繼承來實現介面卡功能;一種是物件介面卡模式,通過組合來實現介面卡功能。
介面卡模式使用場景
電器的電壓,經典的jdbc使用。
介面卡模式優缺點
優點:
提升了類的複用和靈活度。
缺點:
使用過多,系統會比較雜亂,難以把握。
介面卡模式示例圖
橋接模式
橋接模式介紹
橋接是用於把抽象化與實現化解耦,使得二者可以獨立變化。這種型別的設計模式屬於結構型模式,它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。通過一箇中間的橋樑對兩邊的東西進行關聯起來,但是關聯的兩者之間又不相互影響。
橋接模式場景
一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件。
橋接模式優缺點
優點:
1、抽象和實現的分離,實現瞭解耦;
2、提升的擴充套件能力。
缺點:
會使系統看起復雜,對新手不友好,沒有一定的抽象進行設計能力難以理解。
橋接模式示例圖
外觀模式
外觀模式介紹
外觀模式隱藏系統的複雜性,並向客戶端提供了一個客戶端可以訪問系統的介面。它向現有的系統新增一個介面,來隱藏系統的複雜性。對外提供一個簡單介面,隱藏實現的邏輯。
外觀模式使用場景
系統中有多個複雜的模組或者子系統的時候。
外觀模式優缺點
優點:
降低了耦合,從某種方面來說也提升了安全性。
缺點:
不符合開閉原則,不易更改。
外觀模式示例圖
裝飾器模式
裝飾器模式介紹
裝飾器模式允許向一個現有的物件新增新的功能,同時又不改變其結構。這種型別的設計模式屬於結構型模式,它是作為現有的類的一個包裝。
把某個東西進行裝飾起來,讓它可以提供一些額外的功能。
裝飾器模式使用場景
原型不變,動態增加一些功能的時候。
裝飾器模式優缺點
優點:
裝飾類和被裝飾類可以獨立發展,耦合度低,易於擴充套件,靈活方便。
缺點:
過多的對某個類進行裝飾,會增加複雜度。
裝飾器模式示例圖
組合模式
組合模式介紹
組合模式是用於把一組相似的物件當作一個單一的物件。組合模式依據樹形結構來組合物件,用來表示部分以及整體層次。這種型別的設計模式屬於結構型模式,它建立了物件組的樹形結構。
組合模式使用場景
可以表示為 ‘部分-整體’的層級結構。
組合模式優缺點
優點:
高層模組呼叫較為簡單,增加某個節點方便。
缺點:
因為其子節點的宣告都是實現類,而不是介面,違反了依賴倒置原則。
組合模式示例圖
過濾器模式
過濾器模式介紹
過濾器模式允許開發人員使用不同的標準來過濾一組物件,通過邏輯運算以解耦的方式把它們連線起來。這種型別的設計模式屬於結構型模式,它結合多個標準來獲得單一標準。
過濾器模式使用場景
需要進行篩選的時候。
過濾器模式優缺點
優點:
簡單,解耦,使用方便。
缺點:
過多使用需要注意效能。
過濾器模式注意事項
在jdk1.8以後可以使用steam的方法進行過濾分組,可以根據指定的條件進行過濾分組篩選。
享元模式
享元模式介紹
享元模式主要用於減少建立物件的數量,以減少記憶體佔用和提高效能。這種型別的設計模式屬於結構型模式,它提供了減少物件數量從而改善應用所需的物件結構的方式。
享元模式角色
享元模式的角色主要分為三大類,抽象享元類、具體享元類以及享元工廠類。
- 抽象享元類:所有具體享元類的超類或者介面,通過這個介面,可以接受並作用於外部專題。
- 具體享元類:實現抽象享元類介面的功能並增加儲存空間。
- 享元工廠類:用來建立並管理抽象享元類物件,它主要用來確保合理地共享。每當接受到一個請求是,便會提供一個已經建立的抽象享元類物件或者新建一個。 享元模式的核心在於享元工廠類,享元工廠類的作用在於提供一個用於儲存享元物件的享元池,使用者需要物件時,首先從享元池中獲取,如果享元池中不存在 ,則建立一個新的享元物件返回給使用者,並在享元池中儲存該新增物件。
享元模式使用場景
系統有大量相似物件。
享元模式優缺點
優點:
極大的減少物件的建立,從而降低了系統的記憶體,提升了效率。
缺點:
提高了系統的複雜度,因為需要將狀態進行分離成內部和外部,並且也使外部狀態固有化,使得隨著內部狀態的變化而變化,會造成系統的混亂。
享元模式注意事項
需要注意劃分外部狀態和內部狀態,否則可能會引起執行緒安全問題。 這些類必須有一個工廠物件加以控制。
與單例模式比較
雖然它們在某些方面很像,但是實際上卻是不同的東西,單例模式的目的是限制建立多個物件,避免衝突,比如使用資料庫連線池。而享元模式享元模式的目的是共享,避免多次建立耗費資源,比如使用String類。
享元模式示例圖
代理模式
代理模式介紹
主要是通過一個類代表另一個類的功能。通常,我們建立具有現有物件的物件,以便向外界提供功能介面。
代理模式角色
代理模式主要由這三個角色組成,抽象角色、代理角色和真實角色。
- 抽象角色:通過介面或抽象類宣告真實角色實現的業務方法。
- 代理角色:實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作。
- 真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫。
代理模式使用
代理模式又分為靜態代理、動態代理。
- 靜態代理是由程式設計師建立或工具生成代理類的原始碼,再編譯代理類。所謂靜態也就是在程式執行前就已經存在代理類的位元組碼檔案,代理類和委託類的關係在執行前就確定了。
- 動態代理是在實現階段不用關心代理類,而在執行階段才指定哪一個物件。可以使用JDK中
java.lang.reflect
來進行開發。
代理模式使用場景
1、遠端代理。
2、虛擬代理。
3、Copy-on-Write 代理。
4、保護(Protect or Access)代理。
5、Cache代理。
6、防火牆(Firewall)代理。
7、同步化(Synchronization)代理。
8、智慧引用(SmartReference)代理。
代理模式優缺點
優點:
1、職責清晰。
2、高擴充套件性。
3、智慧化。
缺點:
1、由於在客戶端和真實主題之間增加了代理物件,因此有些型別的代理模式可能會造成請求的處理速度變慢。
2、實現代理模式需要額外的工作,有些代理模式的實現非常複雜。
代理模式注意事項
和介面卡模式的區別:介面卡模式主要改變所考慮物件的介面,而代理模式不能改變所代理類的介面。
和裝飾器模式的區別:裝飾器模式為了增強功能,而代理模式是為了加以控制。
代理模式示例圖
行為型模式
責任鏈模式
責任鏈模式介紹
責任鏈模式顧名思義,就是為請求建立了一個接收者物件的鏈。這種模式給予請求的型別,對請求的傳送者和接收者進行解耦。這種型別的設計模式屬於行為型模式。在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個物件不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
簡單的理解的話就是進行層級處理。
責任鏈模式角色
責任鏈模式主要由這三個角色組成,請求接收者介面(Handler)、請求實現者類(ConcreteHandler)和請求傳送者(Client)。
- 請求接收者介面:定義可以處理客戶端請求事項的介面,包含“可連結下一個同樣能處理請求”的物件引用。
- 請求實現者類:實現請求處理介面,並判斷物件本身是否能夠處理本次請求,如果不能完成請求,則交由後繼者來處理。
- 請求傳送者:將請求傳送給第一個接收者物件,並等待請求的回覆。
責任鏈模式使用場景
需要動態指定處理某一組請求時,在不確定接受者的的情況下,向多個物件傳送請求時。
責任鏈模式優缺點
優點:
耦合度低,請求者和執行者並沒有必然的聯絡;
靈活度高,可以通過內部成員來進行更改它們執行的次序;
擴充套件性好,Handler的子類擴充套件非常方便。
缺點:
會在某程度上降低程式的效能,設定不當的話可能會出現迴圈呼叫。
在鏈過長時,會降低程式碼的閱讀性以及增加程式碼的複雜度。
責任鏈模式注意事項
雖然責任鏈模式很靈活,但是犧牲的是一定的效能,因為責任鏈模式是層級處理,在處理資料的有一定的延遲,所所以需要低延遲的情況下,不推薦使用責任鏈模式。
責任鏈模式示例圖
命令模式
命令模式介紹
命令模式顧名思義,是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令。
也就是將一個請求封裝成一個物件,從而可以用不同的請求對客戶進行引數化。
命令模式角色
命令模式主要由這三個角色組成,命令物件(command)、命令執行物件(received)和命令請求物件(invoker)。
- 命令物件:通過介面或抽象類宣告實現的方法。
- 命令執行物件:實現命令物件的方法,並將一個接收者和動作進行繫結,呼叫接收者相應的操作。
- 命令請求物件:用於執行這個請求,可以動態的對命令進行控制。
命令模式使用場景
如果在有類似
命令
需要指定的,就可以用命令模式,比如記錄日誌、撤銷操作命令等。
命令模式優缺點
優點:
耦合度低,請求者和執行者並沒有必然的聯絡;
擴充套件性好,Command的子類可以非常容易地擴充套件。
缺點:
如果命令過多的話,會增加系統的複雜度 。
命令模式示例圖
直譯器模式
直譯器模式介紹
直譯器模式顧名思義,就是對某事物進行解釋。給定一個語言之後,直譯器模式可以定義出其文法的一種表示,並同時提供一個直譯器。客戶端可以使用這個直譯器來解釋這個語言中的句子。
直譯器模式其實就是對某事物進行解釋。
直譯器模式角色
直譯器模式主要由這四個角色組成,抽象表示式(Expression)角色、終結符表示式(Terminal Expression)角色、非終結符表示式(Nonterminal Expression)角色和環境(Context)角色。
- 抽象直譯器:宣告一個所有具體表達式都要實現的抽象介面(或者抽象類),介面中主要是一個interpret()方法,稱為解釋操作。具體解釋任務由它的各個實現類來完成,具體的直譯器分別由終結符直譯器TerminalExpression和非終結符直譯器NonterminalExpression完成。
- 終結符表示式:實現與文法中的元素相關聯的解釋操作,通常一個直譯器模式中只有一個終結符表示式,但有多個例項,對應不同的終結符。終結符一半是文法中的運算單元,比如有一個簡單的公式R=R1+R2,在裡面R1和R2就是終結符,對應的解析R1和R2的直譯器就是終結符表示式。
- 非終結符表示式:文法中的每條規則對應於一個非終結符表示式,非終結符表示式一般是文法中的運算子或者其他關鍵字,比如公式R=R1+R2中,+就是非終結符,解析+的直譯器就是一個非終結符表示式。非終結符表示式根據邏輯的複雜程度而增加,原則上每個文法規則都對應一個非終結符表示式。
- 環境角色:這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些資訊需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。
直譯器模式使用場景
一個簡單的語法規則需要解釋的場景,比如sql。
有重複的問題的時候。
直譯器模式優缺點
優點:
擴充套件性好,子類擴充套件非常方便。
實現簡單。
缺點:
可使用的場景比較少;
類過多的話,會使程式碼臃腫,難以維護;
直譯器模式示例圖
迭代器模式
迭代器模式介紹
迭代器模式用於順序訪問集合物件的元素,不需要知道集合物件的底層表示,屬於行為型模式。 它提供一種方法順序訪問一個聚合物件中各個元素, 而又無須暴露該物件的內部表示。
迭代器模式角色
迭代器模式主要由這四個角色組成,迭代器角色(Iterator)、具體迭代器角色(Concrete Iterator)、容器角色(Container)和具體容器角色(Concrete Container)。
- 迭代器角色(Iterator):通過介面或抽象類宣告實現的方法。
- 具體迭代器角色(Concrete Iterator):具體迭代器角色要實現迭代器介面,並要記錄遍歷中的當前位置。
- 容器角色(Container):容器角色負責提供建立具體迭代器角色的介面。
- 具體容器角色(Concrete Container):具體容器角色實現建立具體迭代器角色的介面——這個具體迭代器角色於該容器的結構相關。
迭代器模式使用場景
需要為聚合物件提供遍歷的功能的時候。
迭代器模式優缺點
優點:
靈活度高,可以通過不同的方式遍歷物件;
擴充套件性好,可以很方便的增加新的聚合類和迭代器類而不用修改之前的程式碼。
缺點:
由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性。
迭代器模式示例圖
訪問者模式
訪問者模式介紹
訪問者模式(VisitorPattern),顧名思義使用了這個模式後就可以在不修改已有程式結構的前提下,通過新增額外的訪問者來完成對已有程式碼功能的提升,它屬於行為模式。訪問者模式的目的是封裝一些施加於某種資料結構元素之上的操作。一旦這些操作需要修改的話,接受這個操作的資料結構則可以保持不變。
其主要目的是將資料結構與資料操作分離。
訪問者模式角色
訪問者模式主要由這五個角色組成,抽象訪問者(Visitor)、具體訪問者(ConcreteVisitor)、抽象節點(Node)、具體節點(ConcreteNode)和結構物件(ObjectStructure)。
- 抽象訪問者(Visitor)角色:聲明瞭一個或者多個方法操作,形成所有的具體訪問者角色必須實現的介面。
- 具體訪問者(ConcreteVisitor)角色:實現抽象訪問者所宣告的介面,也就是抽象訪問者所宣告的各個訪問操作。
- 抽象節點(Node)角色:宣告一個接受操作,接受一個訪問者物件作為一個引數。
- 具體節點(ConcreteNode)角色:實現了抽象節點所規定的接受操作。
- 結構物件(ObjectStructure)角色:有如下的責任,可以遍歷結構中的所有元素。
訪問者模式使用場景
物件結構中物件對應的類很少改變,但經常需要在此物件結構上定義新的操作;
需要對一個物件結構中的物件進行很多不同的並且不相關的操作,而需要避免讓這些操作"汙染"這些物件的類,也不希望在增加新操作時修改這些類。
訪問者模式優缺點
訪問者模式優點:
擴充套件性好,可以在不修改物件結構中的元素的情況下,為物件結構中的元素新增新的功能;
符合單一職責原則,通過訪問者將無關的行為分離,使職責單一;
訪問者模式缺點:
違反了迪米特原則,因為具體元素對訪問者公佈細節;
違反了依賴倒置原則,依賴了具體類,沒有依賴抽象;
物件結構變化困難,若物件結構發生了改變,訪問者的介面和訪問者的實現也都要發生相應的改變;
訪問者模式示例圖
中介者模式
中介者模式介紹
中介者模式(Mediator Pattern),定義了一箇中介物件來封裝一系列物件之間的互動關係。中介者使各個物件之間不需要顯式地相互引用,從而使耦合性降低,而且可以獨立地改變它們之間的互動行為,屬於行為型模式。
其主要的目的是用來降低多個物件和類之間的通訊複雜性。
中介者模式角色
中介者模式主要由這四個角色組成, 抽象中介者(Mediator)、具體中介者(ConcreteMediator)、 抽象同事類(Colleague)和具體同事類(ConcreteColleague) 。
- 抽象中介者(Mediator): 定義了同事物件到中介者物件之間的介面。
- 具體中介者(ConcreteMediator): 實現抽象中介者的方法,它需要知道所有的具體同事類,同時需要從具體的同事類那裡接收資訊,並且向具體的同事類傳送資訊。
- 抽象同事類(Colleague): 定義了中介者物件的介面,它只知道中介者而不知道其他的同事物件。
- 具體同事類(ConcreteColleague) : 每個具體同事類都只需要知道自己的行為即可,但是他們都需要認識中介者。
中介者模式使用場景
通過一箇中間類來封裝多個類中的行為,而又不想生成太多的子類。
中介者模式優缺點
優點:
靈活性高,因為將同事類進行了解耦,使其不必有關聯性;
降低了類的複雜度,將一對多轉化成了一對一;
缺點:
中介者使用過多,會使系統變得複雜難以維護;
中介者模式注意事項
若不明確各個類的職責,那麼就不要進行使用!
和外觀模式、代理模式比較
中介者模式和外觀模式、代理模式比較類似,但是又有不同。
和外觀模式比較,中介者模式中,同事類必須依賴與中介者,中介者也知道同事類;但是外觀模式中,子系統是不需要知道外觀類的存在,並且子系統是可以脫離外觀模式的。
和代理模式,代理模式的核心就是代理作用,主要還是對原先的類進行擴充套件或增加控制,比如進行許可權控制;而中介者模式主要目的是為了減少物件之前的耦合,也就是同事類直接相互獨立,互不影響。
中介者模式示例圖
策略模式
策略模式介紹
策略模式(Strategy Pattern)屬於物件的行為模式。其用意是針對一組演算法,將每一個演算法封裝到具有共同介面的獨立的類中,從而使得它們可以相互替換。策略模式使得演算法可以在不影響到客戶端的情況下發生變化。
其主要目的是通過定義相似的演算法,替換if else 語句寫法,並且可以隨時相互替換。
策略模式角色
策略模式主要由這三個角色組成,環境角色(Context)、抽象策略角色(Strategy)和具體策略角色(ConcreteStrategy)。
- 環境角色(Context):持有一個策略類的引用,提供給客戶端使用。
- 抽象策略角色(Strategy):這是一個抽象角色,通常由一個介面或抽象類實現。此角色給出所有的具體策略類所需的介面。
- 具體策略角色(ConcreteStrategy):包裝了相關的演算法或行為。
策略模式使用場景
如果在一個系統裡面有許多類,它們之間的區別僅在於它們的行為,那麼使用策略模式可以動態地讓一個物件在許多行為中選擇一種行為;
一個系統需要動態地在幾種演算法中選擇一種;
如果一個物件有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現;
策略模式優缺點
優點:
擴充套件性好,可以在不修改物件結構的情況下,為新的演算法進行新增新的類進行實現;
靈活性好,可以對演算法進行自由切換;
缺點:
使用策略類變多,會增加系統的複雜度。;
客戶端必須知道所有的策略類才能進行呼叫;
策略模式示例圖
模板模式
模板模式介紹
模板模式(Template Pattern)中,一個抽象類公開定義了執行它的方法的方式/模板。它的子類可以按需要重寫方法實現,但呼叫將以抽象類中定義的方式進行。 這種型別的設計模式屬於行為型模式。定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。
模板模式,其主要的的思想就是做一個模板,提供給客戶端進行呼叫。
模板模式角色
模板模式主要由抽象模板(Abstract Template)角色和具體模板(Concrete Template)角色組成。
抽象模板(Abstract Template): 定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作叫做基本操作,它們是一個頂級邏輯的組成步驟;定義並實現了一個模板方法。這個模板方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現。頂級邏輯也有可能呼叫一些具體方法。
具體模板(Concrete Template): 實現父類所定義的一個或多個抽象方法,它們是一個頂級邏輯的組成步驟;每一個抽象模板角色都可以有任意多個具體模板角色與之對應,而每一個具體模板角色都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同。
模板模式使用場景
有多個子類共有邏輯相同的方法;
重要的、複雜的方法,可以考慮作為模板方法。
模板模式優缺點
優點:
擴充套件性好,對不變的程式碼進行封裝,對可變的進行擴充套件;
可維護性好,因為將公共程式碼進行了提取,使用的時候直接呼叫即可;
缺點:
因為每一個不同的實現都需要一個子類來實現,導致類的個數增加,會使系統變得複雜;
模板模式注意事項
為防止惡意操作,一般模板方法都加上 final 關鍵詞!
模板模式示例圖
備忘錄模式
備忘錄模式介紹
備忘錄模式(Memento Pattern)用於儲存一個物件的某個狀態,以便在適當的時候恢復物件,該模式屬於行為型模式。
其主要目的是在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。
其主要的的思想就是備份。
備忘錄模式角色
備忘錄模式主要由這三個角色組成,備忘錄角色(Memento)、發起人角色(Originator)和負責人(Caretaker)角色。
- 備忘錄(Memento):主要的功能是包含要被恢復的物件的狀態。
- 發起人(Originator):在建立的時候,會在備忘錄物件中儲存狀態。
- 負責人(Caretaker):主要是負責從備忘錄物件中恢復物件的狀態。
備忘錄模式使用場景
需要儲存/恢復資料的相關狀態場景;
備忘錄模式優缺點
優點
給使用者提供了一種可以恢復狀態的機制,可以使使用者能夠比較方便地回到某個歷史的狀態;
實現了資訊的封裝,使得使用者不需要關心狀態的儲存細節;
缺點
非常的消耗資源;
客戶端必須知道所有的策略類才能進行呼叫;
備忘錄模示例圖
狀態模式
狀態模式介紹
狀態模式(State Pattern)屬於行為型模式,其狀態的物件和一個行為隨著狀態物件改變而改變。
其主要目的解決的是當控制一個物件狀態轉換的條件表示式過於複雜是的情況。把狀態的判斷邏輯轉移到表示不同狀態一系列類中,可以把複雜的判斷簡單化。
主要的的思想就是提供一種狀態,提供給客戶端進行呼叫。
狀態模式角色
狀態模式主要由環境角色(Context)、 抽象狀態(State)和具體狀態(Concrete State)組成。
環境角色(Context): 它定義了客戶程式需要的介面並維護一個具體狀態角色的例項,將與狀態相關的操作委託給當前的具體狀態物件來處理。
- 抽象狀態角色(State): 定義一個介面以封裝使用上下文環境的的一個特定狀態相關的行為。
具體狀態角色(Concrete State):實現抽象狀態定義的介面。
狀態模式使用場景
行為隨狀態改變而改變的場景;
條件、分支語句的代替者。
狀態模式優缺點
優點:
擴充套件性好,將和狀態有關的行為放到一起,增加新的的狀態,只需要改變物件狀態即可改變物件的行為即可;
複用性好,讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數;
缺點:
使用狀態模式會增加系統類和物件的個數,並且該模式的結構與實現都較為複雜,如果使用不當將導致程式結構和程式碼的混亂;
狀態模式對"開閉原則"的支援並不太好,對於可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法切換到新增狀態,而且修改某個狀態類的行為也需修改對應類的原始碼。
狀態模式注意事項
在行為受狀態約束的時候使用狀態模式,而且狀態不超過5個。
和策略模式比較
在學習狀態模式的時候,很容易和策略模式搞混,因為它們實在是太像了,很難區分,在查閱一番資料之後,整理了如下的相同點和區別點。
相同點:
- 它們很容易新增新的狀態或策略,而且不需要修改使用它們的Context物件。
- 它們都符合OCP原則,在狀態模式和策略模式中,Context物件對修改是關閉的,新增新的狀態或策略,都不需要修改Context。
- 它們都會初始化。
- 它們都依賴子類去實現相關行為。
區別點
- 狀態模式的行為是平行性的,不可相互替換的;
- 而策略模式的行為是平等性的,是可以相互替換的。
- 最重要的一個不同之處是,策略模式的改變由客戶端完成;
- 而狀態模式的改變,由環境角色或狀態自己.
狀態模式示例圖
觀察者模式
觀察者模式介紹
觀察者模式又叫釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。觀察者模式定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態上發生變化時,會通知所有觀察者物件,使它們能夠自動更新自己。。
其主要目的是定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。
觀察者模式角色
觀察者模式主要由這四個角色組成,抽象主題角色(Subject)、具體主題角色(ConcreteSubject)、抽象觀察者角色(Observer)和具體觀察者角色(ConcreteObserver)。
- 抽象主題角色(Subject):它把所有觀察者物件的引用儲存到一個聚集裡,每個主題都可以有任何數量的觀察者。抽象主題提供一個介面,可以增加和刪除觀察者物件。
- 具體主題角色(ConcreteSubject):將有關狀態存入具體觀察者物件;在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。
- 抽象觀察者角色(Observer):主要是負責從備忘錄物件中恢復物件的狀態。
觀察者模式使用場景
需要關聯行為的場景;
事件需要建立一個觸發鏈的場景,比如監控;
跨系統的訊息交換場景,比如訊息佇列、事件匯流排的處理機制。
觀察者模式優缺點
優點:
解除耦合,讓耦合的雙方都依賴於抽象,從而使得各自的變換都不會影響另一邊的變換。
缺點
如果一個被觀察者物件有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間;
如果在觀察者和觀察目標之間有迴圈依賴的話,觀察目標會觸發它們之間進行迴圈呼叫,可能導致系統崩潰;
觀察者模式沒有相應的機制讓觀察者知道所觀察的目標物件是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
觀察者模式注意事項
如果順序執行,某一觀察者錯誤會導致系統卡殼,建議採用非同步方式。
觀察者模式示例圖
空物件模式
空物件模式介紹
空物件模式(NullObject Pattern)主要是通過一個空物件取代 NULL 物件例項的檢查。Null 物件不是檢查空值,而是反應一個不做任何動作的關係。 這樣的Null 物件也可以在資料不可用的時候提供預設的行為。
其主要目的是在進行呼叫是不返回Null,而是返回一個空物件,防止空指標異常。
空物件模式使用場景
需要大量對空值進行判斷的時候;
空物件模式優缺點
優點:
可以加強系統的穩固性,能有效防止空指標報錯對整個系統的影響;
不依賴客戶端便可以保證系統的穩定性;
缺點:
需要編寫較多的程式碼來實現空值的判斷,從某種方面來說不划算;
其它
在學習設計模式的時候,主要參考書籍是《大話設計模式》以及菜鳥教程的設計模式介紹。
其實在我們學習了這麼多的設計模式中,大部分可能只是聽說了解過,真正經常使用的設計模式也無外乎就那幾種,單例模式(資料庫、執行緒池場景)、工廠模式(簡單的crud操作中例項化的model)、策略模式(商城會員、優惠打折場景)、觀察者模式(訊息推送場景)、代理模式(主要是動態代理這塊)、外觀模式(一鍵呼叫)、裝飾器模式(錦上添花場景),但是也不全這樣,使用設計模式最好根據實際的場景來使用,否則可能在不合適的場景使用了不適合的設計模式而導致程式碼混亂。
音樂推薦
往期音樂推薦
一、
我們目送 那漸漸消失的行跡雲 在晃眼間消逝 總是如此短暫 如像昨天起 不變的事 始終不會改變 不該存在的東西 帶著遺憾消失在指間
那鳥兒還未能展翅高飛 但它總有一天會破風馳行 遙不可及的地方仍在遠處 所以只能凝視深藏的願望 孩子們走在盛夏的鐵路上 流風輕撫著他們的赤腳 遠離了童年
二、
這世上大部分失落,都是因為我們自己沒成為更好的自己,卻奢求別人成為更好的別人。
三、
平靜孤寂的調子起頭,兩個人分開之後的沉寂 頹廢,慢慢的音階起伏,我意識到不能這樣下去,我開始改變現狀,變得積極。到高潮部分 我不在頹廢,我走了新的目標 我迎著太陽前進。我想這就是You的含義,你是我的一段過去
四、
扶桑畫師淺溪,居泰安,喜繪鯉。院前一方荷塘,錦鯉遊曳,溪常與嬉戲。 其時正武德之亂,藩鎮割據,戰事頻仍,魑魅魍魎,肆逆於道。兵戈逼泰安,街鄰皆逃亡,獨溪不捨錦鯉,未去。 是夜,院室倏火。有人入火護溪,言其本鯉中妖,欲取溪命,卻生情愫,遂不忍為之。翌日天明,火勢漸歇,人已不見。
五、
稚兒擎瓜柳棚下,細犬逐蝶窄巷中,人間繁華多笑語,惟我空餘兩鬢風。
六、
散落的花,火的碎片 誘人的夏夜終結
漸漸 天空閃耀,帶著誰許的願
突然綻放的煙花
美麗如夢幻,遲來脆弱的夏天
夜空中,火花舞動在今夜
枝頭落下的仲夏夜之夢
愉快的涼風,熱帶的夜
天空飄著細雨,在喧鬧的蟬鳴時節
夏末,秋天指向路邊。
七、
論如何一個人在家嗨成狗。取下耳機無限的孤獨感。帶上耳機臥槽我是全世界。
八、
我渴望能見你一面,但請你記得,我不會開口要求見你。這不是因為驕傲,你知道我在你面前毫無驕傲可言,而是因為,唯有你也想見我的時候,我們見面才有意義。 ———《越洋情書》
九、
就算是Believe,中間也藏了一個lie;
就算是Friend,還是免不了end;
就算是Lover,還可能會over;
就算是Wife,心裡也夾雜著if;
欣慰的是:即便是Forget,也曾經get,
就算impossible,但還藏著possible。
十、
人有三樣東西是無法隱瞞的,咳嗽、窮困和愛;你想隱瞞越欲蓋彌彰。人有三樣東西是不該揮霍的,身體、金錢和愛;你想揮霍卻得不償失。人有三樣東西是無法挽留的,時間、生命和愛;你想挽留卻漸行漸遠。人有三樣東西是不該回憶的,災難、死亡和愛;你想回憶卻苦不堪言。 ——《洛麗塔》
十一、
簡單,重複,毫無華麗旋律,也無厚重悲涼的伴奏。但心偏偏就被緊緊的抓住了。一種茫然卻被迫緊湊的感覺。一種不知何所處的心虛。what for?
十二、
輕吟一句情話,執筆一副情畫。 綻放一地情花,覆蓋一片青瓦。 共飲一杯清茶,同研一碗青砂。
挽起一面輕紗,看清天邊月牙。愛像水墨青花,何懼剎那芳華。
十三、
所有人和事,自己問心無愧就好,不是你的也彆強求,反正離去的,都是風景,留下的,才是人生。
以上評論來自網易雲!
專案的程式碼
java-study是本人在學習Java過程中記錄的一些程式碼,也包括之前博文中使用的程式碼。如果感覺不錯,希望順手給個start,當然如果有不足,也希望提出。
github地址: https://github.com/xuwujing/java-study
原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力!
版權宣告:
作者:虛無境
部落格園出處:http://www.cnblogs.com/xuwujing
CSDN出處:http://blog.csdn.net/qazwsxpcm
個人部落格出處:http://www.panchengming.com