本文旨在快速梳理經常使用的設計模式,瞭解每一個模式主要針對的是哪些狀況以及其基礎特徵,每一個模式前都有列舉出一個或多個能夠深刻閱讀的參考網頁,以供讀者詳細瞭解其實現。html
分爲三篇文章:java
全複習手冊文章導航git
點擊公衆號下方:技術推文——面試衝刺github
行爲型算法
首先搞清楚一點,設計模式不是高深技術,不是奇淫技巧。設計模式只是一種設計思想,針對不一樣的業務場景,用不一樣的方式去設計代碼結構,其最最本質的目的是爲了解耦,延伸一點的話,還有爲了可擴展性和健壯性,可是這都是創建在解耦的基礎之上。spring
高內聚:系統中A、B兩個模塊進行交互,若是修改了A模塊,不影響模塊B的工做,那麼認爲A有足夠的內聚。數據庫
低耦合:就是A模塊與B模塊存在依賴關係,那麼當B發生改變時,A模塊仍然能夠正常工做,那麼就認爲A與B是低耦合的。apache
blog.csdn.net/maoyuanming…設計模式
使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈發送該請求,直到有一個對象處理它爲止。
在這種模式中,一般每一個接收者都包含對另外一個接收者的引用。若是一個對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
紅樓夢中的"擊鼓傳花"。 JS 中的事件冒泡。 JAVA WEB 中 Apache Tomcat 對 Encoding 的處理,Struts2 的攔截器,jsp servlet 的 Filter,springMVC的攔截器
什麼時候使用:在處理消息的時候以過濾不少道。
如何解決:攔截的類都實現統一接口。
關鍵代碼:Handler 裏面聚合它本身,在 HandlerRequest 裏判斷是否合適,若是沒達到條件則向下傳遞,向誰傳遞以前 set 進去。
處理器的抽象類
package com.mym.designmodel.CoRModel;
/**
* 職責:Handler 職責類的抽象父類
*/
public abstract class AbstractCarHandler {
AbstractCarHandler carHandler = null;
public abstract void carHandler();
public AbstractCarHandler setNextCarHandler(AbstractCarHandler nextCarHandler){
this.carHandler = nextCarHandler;
return this.carHandler;
}
/**職責下傳*/
protected void doChain(){
if(this.carHandler != null){
this.carHandler.carHandler();
}
}
}
複製代碼
責任鏈一個執行者1
package com.mym.designmodel.CoRModel;
/**
* 職責:concreteHandler 具體的處理類
*/
public class CarHeadHandler extends AbstractCarHandler {
@Override
public void carHandler() {
System.out.println("處理車的head!");
//下傳
this.doChain();
}
}
複製代碼
責任鏈一個執行者2
package com.mym.designmodel.CoRModel;
/**
* 職責:concreteHandler 具體的處理類
*/
public class CarBodyHandler extends AbstractCarHandler {
@Override
public void carHandler() {
System.out.println("處理車的body!");
//下傳
this.doChain();
}
}
複製代碼
責任鏈一個執行者3
package com.mym.designmodel.CoRModel;
/**
* 職責:concreteHandler 具體的處理類
*/
public class CarTailHandler extends AbstractCarHandler {
@Override
public void carHandler() {
System.out.println("處理車的tail!");
//下傳
this.doChain();
}
}
複製代碼
客戶端client
package com.mym.designmodel.CoRModel;
/**
* 測試
*/
public class MainClass {
public static void main(String[] args) {
AbstractCarHandler carheadHandle = new CarHeadHandler();
AbstractCarHandler carbodyHandle = new CarBodyHandler();
AbstractCarHandler carTailHandler = new CarTailHandler();
//組裝責任鏈
carheadHandle.setNextCarHandler(carbodyHandle).setNextCarHandler(carTailHandler);
//鏈頭部開始執行
carheadHandle.carHandler();
}
}
複製代碼
命令模式是爲了解決命令的請求者和命令的實現者之間的耦合關係。
解決了這種耦合的好處我認爲主要有兩點:
1.更方便的對命令進行擴展(注意:這不是主要的優點,後面會提到)
2.對多個命令的統一控制(這種控制包括但不限於:隊列、撤銷/恢復、記錄日誌等等)
struts 1 中的 action 核心控制器 ActionServlet 只有一個,至關於 Invoker,而模型層的類會隨着不一樣的應用有不一樣的模型類,至關於具體的 Command。
所謂解釋器模式就是定義語言的文法,而且創建一個解釋器來解釋該語言中的句子。
這種模式實現了一個表達式接口,該接口解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。
編譯器、運算表達式計算。
提供一種順序訪問聚合對象元素的方法,而且不暴露聚合對象的內部表示。
優勢
①簡化了遍歷方式,對於對象集合的遍歷,仍是比較麻煩的,對於數組或者有序列表,咱們尚能夠經過遊標來取得,但用戶須要在對集合瞭解很清楚的前提下,自行遍歷對象,可是對於hash表來講,用戶遍歷起來就比較麻煩了。而引入了迭代器方法後,用戶用起來就簡單的多了。
②能夠提供多種遍歷方式,好比說對有序列表,咱們能夠根據須要提供正序遍歷,倒序遍歷兩種迭代器,用戶用起來只須要獲得咱們實現好的迭代器,就能夠方便的對集合進行遍歷了。
③封裝性良好,用戶只須要獲得迭代器就能夠遍歷,而對於遍歷算法則不用去關心。
缺點
對於比較簡單的遍歷(像數組或者有序列表),使用迭代器方式遍歷較爲繁瑣,你們可能都有感受,像ArrayList,咱們寧肯願意使用for循環和get方法來遍歷集合。
集中相關對象之間複雜的溝通和控制方式。
Alarm(鬧鐘)、CoffeePot(咖啡壺)、Calendar(日曆)、Sprinkler(噴頭)是一組相關的對象,在某個對象的事件產生時須要去操做其它對象,造成了下面這種依賴結構:
使用中介者模式能夠將複雜的依賴結構變成星形結構:
在不違反封裝的狀況下得到對象的內部狀態,從而在須要時能夠將對象恢復到最初狀態。
所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣能夠在之後將對象恢復到原先保存的狀態。
一、後悔藥。 二、打遊戲時的存檔。 三、Windows 裏的 ctri + z。 四、IE 中的後退。 五、數據庫的事務管理。
觀察者模式是對象的行爲模式,又叫發佈-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生變化時,會通知全部觀察者對象,使它們可以自動更新本身。
一個對象(目標對象)的狀態發生改變,全部的依賴對象(觀察者對象)都將獲得通知,進行廣播通知。
天氣數據佈告板會在天氣信息發生改變時更新其內容,佈告板有多個,而且在未來會繼續增長。
容許對象在內部狀態改變時改變它的行爲,對象看起來好像修改了它所屬的類。
考慮一個在線投票系統的應用,要實現控制同一個用戶只能投一票,若是一個用戶反覆投票,並且投票次數超過5次,則斷定爲惡意刷票,要取消該用戶投票的資格,固然同時也要取消他所投的票;若是一個用戶的投票次數超過8次,將進入黑名單,禁止再登陸和使用系統。
定義一系列算法,封裝每一個算法,並使它們能夠互換。
策略模式和狀態模式的區別:
之因此說狀態模式是策略模式的孿生兄弟,是由於它們的UML圖是同樣的,但意圖卻徹底不同,**策略模式是讓用戶指定更換的策略算法,而狀態模式是狀態在知足必定條件下的自動更換,用戶沒法指定狀態,最多隻能設置初始狀態。 **
策略模式可讓算法獨立於使用它的客戶端。
假設如今要設計一個販賣各種書籍的電子商務網站的購物車系統。一個最簡單的狀況就是把全部貨品的單價乘上數量,可是實際狀況確定比這要複雜。好比,本網站可能對全部的高級會員提供每本20%的促銷折扣;對中級會員提供每本10%的促銷折扣;對初級會員沒有折扣。
根據描述,折扣是根據如下的幾個算法中的一個進行的:
算法一:對初級會員沒有折扣。
算法二:對中級會員提供10%的促銷折扣。
算法三:對高級會員提供20%的促銷折扣。
public static void main(String[] args) {
//選擇並建立須要使用的策略對象
MemberStrategy strategy = new AdvancedMemberStrategy();
//建立環境
Price price = new Price(strategy);
//計算價格
double quote = price.quote(300);
System.out.println("圖書的最終價格爲:" + quote);
}
複製代碼
經過讓環境類持有一個抽象策略類(超類)的引用,在生成環境類實例對象時,讓該引用指向具體的策略子類。再對應的方法調用中,就會經過Java的多態,調用對應策略子類的方法。從而能夠相互替換,不須要修改環境類內部的實現。同時,在有新的需求的狀況下,也只須要修改策略類便可,下降與環境類之間的耦合度。
工廠模式和策略模式的區別在於實例化一個對象的位置不一樣,對工廠模式而言,實例化對象是放在服務端的,即放在了工廠類裏面; 而策略模式實例化對象的操做在客戶端
工廠模式要求服務端的銷售部門足夠靈敏,而策略模式因爲對策略進行了封裝,因此他的銷售部門比較傻,須要客戶提供足夠能區分使用哪一種策略的參數,而這最好的就是該策略的實例了。
典型用例:Spring
模板方法模式是類的行爲模式。
準備一個抽象類,將部分邏輯以具體方法以及具體構造函數的形式實現,而後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不一樣的子類能夠以不一樣的方式實現這些抽象方法,從而對剩餘的邏輯有不一樣的實現。這就是模板方法模式的用意。
模板方法中的方法能夠分爲兩大類:模板方法和基本方法。
一個模板方法是定義在抽象類中的,把基本操做方法組合在一塊兒造成一個總算法或一個總行爲的方法。
一個抽象類能夠有任意多個模板方法,而不限於一個。每個模板方法均可以調用任意多個具體方法。
基本方法又能夠分爲三種
抽象方法:一個抽象方法由抽象類聲明,由具體子類實現。在Java語言裏抽象方法以abstract關鍵字標示。
具體方法:一個具體方法由抽象類聲明並實現,而子類並不實現或置換。
鉤子方法:一個鉤子方法由抽象類聲明並實現,而子類會加以擴展。一般抽象類給出的實現是一個空實現,做爲方法的默認實現。
默認鉤子方法
一個鉤子方法經常由抽象類給出一個空實現做爲此方法的默認實現。這種空的鉤子方法叫作「Do Nothing Hook」。具體模版類中能夠選擇是否重寫鉤子方法,一般重寫鉤子方法是爲了對模版方法中的步驟進行控制,判斷鉤子方法中的狀態,是否進行下一步操做。
模板方法模式是基於繼承的代碼複用技術,它體現了面向對象的諸多重要思想,是一種使用較爲頻繁的模式。模板方法模式普遍應用於框架設計中,以確保經過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設置等)。
好比我有一個帳單,帳單有收入,支出兩個固定方法。可是訪問帳單的人不肯定,有多是一個或者多個。
通常被訪問的東西所持有的方法是固定的,就像帳單隻有收入和支出兩個功能。而訪問者是不固定的。
數據操做與數據結構相分離:頻繁的更改數據,但不結構不變。好比:雖然每一天帳單的數據都會變化(數據變化),可是隻有兩類數據,就是支出和收入(結構不變)。
見參考網頁
使用什麼都不作的空對象來代替 NULL。
一個方法返回 NULL,意味着方法的調用端須要去檢查返回值是不是 NULL,這麼作會致使很是多的冗餘的檢查代碼。而且若是某一個調用端忘記了作這個檢查返回值,而直接使用返回的對象,那麼就有可能拋出空指針異常。
更多精彩文章,請查閱個人博客或關注個人公衆號:Rude3Knife
全複習手冊文章導航
點擊公衆號下方:技術推文——面試衝刺
知識點複習手冊文章推薦
我是蠻三刀把刀,目前爲後臺開發工程師。主要關注後臺開發,網絡安全,Python爬蟲等技術。
來微信和我聊聊:yangzd1102
Github:github.com/qqxx6661
同步更新如下博客
1. Csdn
擁有專欄:Leetcode題解(Java/Python)、Python爬蟲開發、面試助攻手冊
2. 知乎
擁有專欄:碼農面試助攻手冊
3. 掘金
4. 簡書
若是文章對你有幫助,不妨收藏起來並轉發給您的朋友們~