快速梳理經常使用的設計模式(中篇)

前言

本文旨在快速梳理經常使用的設計模式,瞭解每一個模式主要針對的是哪些狀況以及其基礎特徵,每一個模式前都有列舉出一個或多個能夠深刻閱讀的參考網頁,以供讀者詳細瞭解其實現。html

分爲三篇文章:java

  • 上篇:設計模式基礎理念和建立型設計模式
  • 中篇:行爲型設計模式
  • 下篇:結構型設計模式

面試知識點複習手冊

全複習手冊文章導航git

點擊公衆號下方:技術推文——面試衝刺github

全複習手冊文章導航(CSDN)面試

快速回憶

行爲型算法

  • 責任鏈(Chain Of Responsibility)
  • 命令(Command)
  • 解釋器(Interpreter)
  • 迭代器(Iterator)
  • 中介者(Mediator)
  • 備忘錄(Memento)
  • 觀察者(Observer)
  • 狀態(State)
  • 策略(Strategy)
  • 模板方法(Template Method)
  • 訪問者(Visitor)
  • 空對象(Null)

理念

首先搞清楚一點,設計模式不是高深技術,不是奇淫技巧。設計模式只是一種設計思想,針對不一樣的業務場景,用不一樣的方式去設計代碼結構,其最最本質的目的是爲了解耦,延伸一點的話,還有爲了可擴展性和健壯性,可是這都是創建在解耦的基礎之上。spring

高內聚低耦合

高內聚:系統中A、B兩個模塊進行交互,若是修改了A模塊,不影響模塊B的工做,那麼認爲A有足夠的內聚。數據庫

低耦合:就是A模塊與B模塊存在依賴關係,那麼當B發生改變時,A模塊仍然能夠正常工做,那麼就認爲A與B是低耦合的。apache

行爲型

責任鏈(Chain Of Responsibility)

blog.csdn.net/maoyuanming…設計模式

意圖

使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈發送該請求,直到有一個對象處理它爲止。

在這種模式中,一般每一個接收者都包含對另外一個接收者的引用。若是一個對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。

職責和角色

  • Handler:處理類的抽象父類
  • concreteHandler:具體的處理類

設計使用責任鏈的基本流程

  • 組織對象鏈:將某人物的全部職責執行對象以鏈的形式加以組織起來
  • 消息或請求的傳遞:將消息或請求沿着對象鏈傳遞,讓處於對象鏈中的對象獲得處理機會
  • 對象鏈中對象的職責分配:不一樣對象完成不一樣職責
  • 任務的完成:對象鏈末尾的對象結束任務並中止消息或請求的繼續傳遞。

應用實例

紅樓夢中的"擊鼓傳花"。 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();
    }
}
複製代碼

JDK

命令(Command)

www.cnblogs.com/konck/p/419…

意圖

命令模式是爲了解決命令的請求者和命令的實現者之間的耦合關係。

解決了這種耦合的好處我認爲主要有兩點:

1.更方便的對命令進行擴展(注意:這不是主要的優點,後面會提到)

2.對多個命令的統一控制(這種控制包括但不限於:隊列、撤銷/恢復、記錄日誌等等)

應用實例

struts 1 中的 action 核心控制器 ActionServlet 只有一個,至關於 Invoker,而模型層的類會隨着不一樣的應用有不一樣的模型類,至關於具體的 Command。

類圖

  • Command:命令
  • Receiver:命令接收者,也就是命令真正的執行者
  • Invoker:經過它來調用命令
  • Client:能夠設置命令與命令的接收者

JDK

解釋器(Interpreter)

www.cnblogs.com/chenssy/p/3…

意圖

所謂解釋器模式就是定義語言的文法,而且創建一個解釋器來解釋該語言中的句子。

這種模式實現了一個表達式接口,該接口解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。

應用實例

編譯器、運算表達式計算。

JDK

迭代器(Iterator)

www.jianshu.com/p/3d0406a01…

意圖

提供一種順序訪問聚合對象元素的方法,而且不暴露聚合對象的內部表示。

迭代器模式的優缺點

優勢

①簡化了遍歷方式,對於對象集合的遍歷,仍是比較麻煩的,對於數組或者有序列表,咱們尚能夠經過遊標來取得,但用戶須要在對集合瞭解很清楚的前提下,自行遍歷對象,可是對於hash表來講,用戶遍歷起來就比較麻煩了。而引入了迭代器方法後,用戶用起來就簡單的多了。

②能夠提供多種遍歷方式,好比說對有序列表,咱們能夠根據須要提供正序遍歷,倒序遍歷兩種迭代器,用戶用起來只須要獲得咱們實現好的迭代器,就能夠方便的對集合進行遍歷了。

③封裝性良好,用戶只須要獲得迭代器就能夠遍歷,而對於遍歷算法則不用去關心。

缺點

對於比較簡單的遍歷(像數組或者有序列表),使用迭代器方式遍歷較爲繁瑣,你們可能都有感受,像ArrayList,咱們寧肯願意使用for循環和get方法來遍歷集合。

JDK

中介者(Mediator)

www.runoob.com/design-patt…

意圖

集中相關對象之間複雜的溝通和控制方式。

實現

Alarm(鬧鐘)、CoffeePot(咖啡壺)、Calendar(日曆)、Sprinkler(噴頭)是一組相關的對象,在某個對象的事件產生時須要去操做其它對象,造成了下面這種依賴結構:

在這裏插入圖片描述

使用中介者模式能夠將複雜的依賴結構變成星形結構:

在這裏插入圖片描述

JDK

備忘錄(Memento)

blog.csdn.net/o279642707/…

意圖

在不違反封裝的狀況下得到對象的內部狀態,從而在須要時能夠將對象恢復到最初狀態。

主要解決

所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣能夠在之後將對象恢復到原先保存的狀態。

應用實例

一、後悔藥。 二、打遊戲時的存檔。 三、Windows 裏的 ctri + z。 四、IE 中的後退。 五、數據庫的事務管理。

JDK

  • java.io.Serializable

觀察者(Observer)

www.jianshu.com/p/fc4554cda…

意圖

觀察者模式是對象的行爲模式,又叫發佈-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。

觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生變化時,會通知全部觀察者對象,使它們可以自動更新本身。

在這裏插入圖片描述

什麼時候使用

一個對象(目標對象)的狀態發生改變,全部的依賴對象(觀察者對象)都將獲得通知,進行廣播通知。

實現舉例

天氣數據佈告板會在天氣信息發生改變時更新其內容,佈告板有多個,而且在未來會繼續增長。

在這裏插入圖片描述

JDK

狀態(State)

www.cnblogs.com/java-my-lif…

意圖

容許對象在內部狀態改變時改變它的行爲,對象看起來好像修改了它所屬的類。

應用實例

考慮一個在線投票系統的應用,要實現控制同一個用戶只能投一票,若是一個用戶反覆投票,並且投票次數超過5次,則斷定爲惡意刷票,要取消該用戶投票的資格,固然同時也要取消他所投的票;若是一個用戶的投票次數超過8次,將進入黑名單,禁止再登陸和使用系統。

策略(Strategy)

www.jianshu.com/p/7fa8ad000…

www.cnblogs.com/wenjiang/p/…

意圖

定義一系列算法,封裝每一個算法,並使它們能夠互換。

策略模式和狀態模式的區別:

之因此說狀態模式是策略模式的孿生兄弟,是由於它們的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的多態,調用對應策略子類的方法。從而能夠相互替換,不須要修改環境類內部的實現。同時,在有新的需求的狀況下,也只須要修改策略類便可,下降與環境類之間的耦合度。

策略模式和工廠方法的異同

工廠模式和策略模式的區別在於實例化一個對象的位置不一樣,對工廠模式而言,實例化對象是放在服務端的,即放在了工廠類裏面; 而策略模式實例化對象的操做在客戶端

工廠模式要求服務端的銷售部門足夠靈敏,而策略模式因爲對策略進行了封裝,因此他的銷售部門比較傻,須要客戶提供足夠能區分使用哪一種策略的參數,而這最好的就是該策略的實例了。

JDK

  • java.util.Comparator#compare()
  • javax.servlet.http.HttpServlet
  • javax.servlet.Filter#doFilter()

模板方法(Template Method)

www.jianshu.com/p/cc391b56b…

典型用例:Spring

定義

模板方法模式是類的行爲模式。

準備一個抽象類,將部分邏輯以具體方法以及具體構造函數的形式實現,而後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不一樣的子類能夠以不一樣的方式實現這些抽象方法,從而對剩餘的邏輯有不一樣的實現。這就是模板方法模式的用意。

結構

模板方法中的方法能夠分爲兩大類:模板方法和基本方法。

模板方法

一個模板方法是定義在抽象類中的,把基本操做方法組合在一塊兒造成一個總算法或一個總行爲的方法。

一個抽象類能夠有任意多個模板方法,而不限於一個。每個模板方法均可以調用任意多個具體方法。

基本方法

基本方法又能夠分爲三種

  • 抽象方法:一個抽象方法由抽象類聲明,由具體子類實現。在Java語言裏抽象方法以abstract關鍵字標示。

  • 具體方法:一個具體方法由抽象類聲明並實現,而子類並不實現或置換。

  • 鉤子方法:一個鉤子方法由抽象類聲明並實現,而子類會加以擴展。一般抽象類給出的實現是一個空實現,做爲方法的默認實現。

默認鉤子方法

一個鉤子方法經常由抽象類給出一個空實現做爲此方法的默認實現。這種空的鉤子方法叫作「Do Nothing Hook」。具體模版類中能夠選擇是否重寫鉤子方法,一般重寫鉤子方法是爲了對模版方法中的步驟進行控制,判斷鉤子方法中的狀態,是否進行下一步操做。

使用場景

模板方法模式是基於繼承的代碼複用技術,它體現了面向對象的諸多重要思想,是一種使用較爲頻繁的模式。模板方法模式普遍應用於框架設計中,以確保經過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設置等)。

JDK

  • java.util.Collections#sort()
  • java.io.InputStream#skip()
  • java.io.InputStream#read()
  • java.util.AbstractList#indexOf()

訪問者(Visitor)

www.jianshu.com/p/80b9cd7c0…

什麼是訪問者模式?

好比我有一個帳單,帳單有收入,支出兩個固定方法。可是訪問帳單的人不肯定,有多是一個或者多個。

訪問者模式有兩個特色

通常被訪問的東西所持有的方法是固定的,就像帳單隻有收入和支出兩個功能。而訪問者是不固定的。

數據操做與數據結構相分離:頻繁的更改數據,但不結構不變。好比:雖然每一天帳單的數據都會變化(數據變化),可是隻有兩類數據,就是支出和收入(結構不變)。

代碼

見參考網頁

空對象(Null)

意圖

使用什麼都不作的空對象來代替 NULL。

一個方法返回 NULL,意味着方法的調用端須要去檢查返回值是不是 NULL,這麼作會致使很是多的冗餘的檢查代碼。而且若是某一個調用端忘記了作這個檢查返回值,而直接使用返回的對象,那麼就有可能拋出空指針異常。

-----正文結束-----

更多精彩文章,請查閱個人博客或關注個人公衆號:Rude3Knife

全複習手冊文章導航

點擊公衆號下方:技術推文——面試衝刺

全複習手冊文章導航(CSDN)

知識點複習手冊文章推薦

關注我

我是蠻三刀把刀,目前爲後臺開發工程師。主要關注後臺開發,網絡安全,Python爬蟲等技術。

來微信和我聊聊:yangzd1102

Github:github.com/qqxx6661

原創博客主要內容

  • 筆試面試複習知識點手冊
  • Leetcode算法題解析(前150題)
  • 劍指offer算法題解析
  • Python爬蟲相關技術分析和實戰
  • 後臺開發相關技術分析和實戰

同步更新如下博客

1. Csdn

blog.csdn.net/qqxx6661

擁有專欄:Leetcode題解(Java/Python)、Python爬蟲開發、面試助攻手冊

2. 知乎

www.zhihu.com/people/yang…

擁有專欄:碼農面試助攻手冊

3. 掘金

juejin.im/user/5b4801…

4. 簡書

www.jianshu.com/u/b5f225ca2…

我的公衆號:Rude3Knife

我的公衆號:Rude3Knife

若是文章對你有幫助,不妨收藏起來並轉發給您的朋友們~

相關文章
相關標籤/搜索