設計模式分類及常用設計模式


引言

對於設計模式,應該明白不同的設計用來解決什么場景問題,對於常用的設計模式能夠靈活運用。

設計模式分類

模式分類有助於更快地學習模式,並且對發現新的模式也有指導作用。

根據兩條原則進行分類。

第一是目的准則,即模式是用來完成什么工作的。模式依據其目的分為創建型、結構型、行為型三種。

創建型模式與對象的創建有關;結構型模式處理類或對象的組合;行為型模式對類或對象怎樣交互和怎樣分配職責進行描述。

第二條是范圍准則,指定模式主要是用於類還是用於對象。

類模式處理類和子類之間的關系,這些關系通過繼承建立,是靜態的,在編譯時刻便確定下來了。

對象模式處理對象之間的關系,這些關系在運行時刻是可以變化的,更具動態性。

從某種意義上來說,幾乎所有模式都是用繼承機制,所以“類模式”只指那些集中於處理類間關系的模式,而大部分模式都屬於對象模式的范疇。

 

類模式

對象模式

創建型

將對象的部分創建工作延遲到子類

將對象部分的創建工作延遲到另一個對象中

結構型

使用繼承機制來組合類

描述了對象的組裝方式

行為型

使用繼承描述算法和控制流

描述一組對象怎樣協作完成單個對象所無法完成的任務

還有其他組織模式的方式。有些模式經常會被綁在一起使用,有些模式是可替代的,有些模式盡管使用意圖不同但產生的設計結果是很相似的。

還有一種方式是根據模式的“相關模式”部分所描述的他們怎樣互相引用來組織設計模式。

顯然存在着許多組織設計模式的方法。從多角度思考模式有助於對他們的功能、差異和應用場合的更深入理解。

 

 

 

創建型

  1. 單例模式
  2. 工廠方法模式
  3. 抽象工廠模式
  4. 建造者模式
  5. 原型模式

結構型

  1. 適配器模式
  2. 裝飾器模式
  3. 代理模式
  4. 外觀模式
  5. 橋接模式
  6. 組合模式
  7. 享元模式

行為型

  1. 策略模式
  2. 模板方法模式
  3. 觀察者模式
  4. 迭代子模式
  5. 責任鏈模式
  6. 命令模式
  7. 備忘錄模式
  8. 狀態模式
  9. 訪問者模式
  10. 中介者模式
  11. 解釋器模式

下面重點介紹幾種常用的設計模式。

常用設計模式

下面結合設計模式的實際應用,來介紹常用的設計模式,如下圖所示。在面試時遇到類似問題,記得要將設計模式與實際業務場景進行結合,來體現對設計模式的理解和應用能力。

          

單例模式

首先是單例模式,這個模式在實際業務中會經常用到,也是設計模式中的主要考察點。這里介紹線程安全的單例模式實現方式。

單例模式常見的實現方式有三種。

  • 第一種是靜態初始化方式,也叫作餓漢方式。實現的思路就是在類初始化時完成單例實例的創建,因此不會產生並發問題,在這種方式下不管是否會使用到這個單例,都會創建這個單例。

  • 第二種實現方式是雙重檢查,也叫作懶漢方式,只有在真正用到這個單例實例的時候才會去創建,如果沒有使用就不會創建。這個方式必然會面對多個線程同時使用實例時的並發問題。為了解決並發訪問問題,通過 synchronized 或者 lock 進行雙重檢查,保證只有一個線程能夠創建實例。這里要注意內存可見性引起的並發問題,必須使用 volatile 關鍵字修飾單例變量。

  • 第三種是單例注冊表方式,Spring 中 Bean 的單例模式就是通過單例注冊表方式實現的

第二種雙重檢查, 代碼示例 SingletonDoubleCheckedLocking.java

package com.xgcd.singletonPattern;

/**
 * 雙重鎖/雙檢鎖/雙重校驗鎖
 * <p>
 * 也是懶加載的方式
 * 線程安全
 * 這種方式采用雙鎖機制,安全且在多線程情況下能保持高性能。
 * getInstance() 的性能對應用程序很關鍵。
 */
public class SingletonDoubleCheckedLocking {
    // 必須使用 volatile 關鍵字修飾單例變量
    // 作用: 1.保證可見性。使用 volatile 定義的變量,將會保證對所有線程的可見性。
    //      2.禁止指令重排序優化。
    // 由於 volatile 禁止對象創建時指令之間重排序,所以其他線程不會訪問到一個未初始化的對象,從而保證安全性。
    // 注意,volatile禁止指令重排序在 JDK 5 之后才被修復
    private static volatile SingletonDoubleCheckedLocking instance;

    private SingletonDoubleCheckedLocking() {

    }

    public static SingletonDoubleCheckedLocking getInstance() {
        // 多線程程序中,不用讓每個線程每次都加鎖,而只是在實例未被創建的時候再加鎖處理.同時也能保證多線程的安全.這種做法被稱為 double-checked locking(雙重鎖定)
        if (instance == null) {
            synchronized (SingletonDoubleCheckedLocking.class) {
                // 對於instance情況,直接返回instance
                // 當instance為null並且同時有兩個線程調用getInstance方法時,他們將都可以通過第一重instance==null的判斷
                // 然后由於lock機制,這兩個線程則只有一個進入,另一個在外排隊等候,必須要其中的一個進入並出來后,另一個才能進入
                // 而此時如果沒有了第二重的instance==null的判斷,則第一個線程創建了實例,而第二個線程還是可以繼續再創建新的實例,這就沒有達到單例的目的
                // 所以采用兩次instance==null的判斷
                if (instance == null) {
                    instance = new SingletonDoubleCheckedLocking();
                }
            }
        }
        return instance;
    }
}

 

volatile關鍵字: 為什么雙重檢查鎖模式需要 volatile ?

單例注冊表與 Spring 實現單例剖析

 

工廠模式

工廠模式是創建不同類型實例時常用的方式,例如 Spring 中的各種 Bean 是由不同 Bean 工廠類進行創建的

代理模式

代理模式,主要用在不適合或者不能直接引用另一個對象的場景,可以通過代理模式對被代理對象的訪問行為進行控制。Java 的代理模式分為靜態代理和動態代理。靜態代理指在編譯時就已經創建好了代理類,例如在源代碼中編寫的類;動態代理指在 JVM 運行過程中動態創建的代理類,使用動態代理的方法有 JDK 動態代理、CGLIB、Javassist 等。面試時遇到這個問題可以舉個動態代理的例子,比如在 Motan RPC 中,是使用 JDK 的動態代理,通過反射把遠程請求進行封裝,使服務看上去就像在使用本地的方法。

責任鏈模式

Chain of Responsibility 使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系. 將這個對象連成一條鏈, 並沿着這條鏈傳遞該請求, 直到有一個對象處理它為止.

責任鏈模式有點像工廠的流水線,鏈上每一個節點完成對對象的某一種處理,例如 Netty 框架在處理消息時使用的 Pipeline 就是一種責任鏈模式。

適配器模式

適配器模式,類似於我們常見的轉接頭,把兩種不匹配的對象來進行適配,也可以起到對兩個不同的對象進行解藕的作用。例如我們常用的日志處理框架 SLF4J,如果我們使用了 SLF4J 就可以跟 Log4j 或者 Logback 等具體的日志實現框架進行解藕。通過不同適配器將 SLF4J 與 Log4j 等實現框架進行適配,完成日志功能的使用。

觀察者模式

觀察者模式也被稱作發布訂閱模式,適用於一個對象的某個行為需要觸發一系列事件的場景,例如 gRPC 中的 Stream 流式請求的處理就是通過觀察者模式實現的。

構造者模式

構造者模式,適用於一個對象有很多復雜的屬性,需要根據不同情況創建不同的具體對象,例如創建一個 PB 對象時使用的 builder 方式。

 

擴展


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM