知識庫 / Spring RSS 訂閱

Java 責任鏈模式

Spring
HongKong
4
02:05 PM · Dec 06 ,2025

1. 簡介

本文將探討一種廣泛使用的行為設計模式:責任鏈模式

我們可以在上一篇文章中找到更多設計模式。

2. 職責鏈模式

維基百科 將職責鏈模式定義為“包含命令對象源以及一系列處理對象”的設計模式。

鏈中的每個處理對象負責特定類型的命令,處理完成後,會將命令轉發到鏈中的下一個處理對象。

職責鏈模式適用於:

  • 解耦命令發送者和接收者
  • 在處理時選擇處理策略

那麼,讓我們來看一個簡單的示例。

3. 示例

我們將使用責任鏈模式來創建一個用於處理身份驗證請求的鏈條。

因此,輸入身份驗證提供者將是 命令,而每個身份驗證處理程序將是一個單獨的 處理器對象。

我們首先創建一個用於處理程序的基本抽象類:

public abstract class AuthenticationProcessor {

    public AuthenticationProcessor nextProcessor;
    
    // standard constructors

    public abstract boolean isAuthorized(AuthenticationProvider authProvider);
}

接下來,讓我們創建具體的處理器,這些處理器將擴展 AuthenticationProcessor

public class OAuthProcessor extends AuthenticationProcessor {

    public OAuthProcessor(AuthenticationProcessor nextProcessor) {
        super(nextProcessor);
    }

    @Override
    public boolean isAuthorized(AuthenticationProvider authProvider) {
        if (authProvider instanceof OAuthTokenProvider) {
            return true;
        } else if (nextProcessor != null) {
            return nextProcessor.isAuthorized(authProvider);
        }
        
        return false;
    }
}
public class UsernamePasswordProcessor extends AuthenticationProcessor {

    public UsernamePasswordProcessor(AuthenticationProcessor nextProcessor) {
        super(nextProcessor);
    }

    @Override
    public boolean isAuthorized(AuthenticationProvider authProvider) {
        if (authProvider instanceof UsernamePasswordProvider) {
            return true;
        } else if (nextProcessor != null) {
            return nextProcessor.isAuthorized(authProvider);
        }
    return false;
    }
}

以下是翻譯後的內容:

在這裏,我們創建了兩個用於處理傳入授權請求的具體處理器:UsernamePasswordProcessorOAuthProcessor

對於每個處理器,我們都覆蓋了 isAuthorized 方法。

現在,我們來創建一些測試用例:

public class ChainOfResponsibilityTest {

    private static AuthenticationProcessor getChainOfAuthProcessor() {
        AuthenticationProcessor oAuthProcessor = new OAuthProcessor(null);
        return new UsernamePasswordProcessor(oAuthProcessor);
    }

    @Test
    public void givenOAuthProvider_whenCheckingAuthorized_thenSuccess() {
        AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor();
        assertTrue(authProcessorChain.isAuthorized(new OAuthTokenProvider()));
    }

    @Test
    public void givenSamlProvider_whenCheckingAuthorized_thenSuccess() {
        AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor();
 
        assertFalse(authProcessorChain.isAuthorized(new SamlTokenProvider()));
    }
}

上面的示例創建了一個身份驗證處理鏈:UsernamePasswordProcessor -> OAuthProcessor。 在第一個測試中,授權成功,而在其他測試中,授權失敗。

首先,UsernamePasswordProcessor 檢查身份提供者是否為 UsernamePasswordProvider 實例。

由於這不是預期的輸入,UsernamePasswordProcessor 將委託給 OAuthProcessor

最後,OAuthProcessor 處理命令。 在第一個測試中,存在匹配項並且測試通過。 在第二個測試中,鏈中的處理器數量不足,因此測試失敗。

4. 實現原則

在實現鏈式責任模式時,我們需要牢記以下重要原則:

  • 鏈中的每個處理器都將擁有處理命令的實現
    • 在上面的示例中,所有處理器都擁有 isAuthorized 的實現
  • 鏈中的每個處理器都應該擁有指向下一個處理器的引用
    • 上面,UsernamePasswordProcessor 委託給 OAuthProcessor
  • 每個處理器負責將命令委託給下一個處理器,因此要小心命令丟失的情況
    • 再次在上面的示例中,如果命令是 SamlProvider 的實例,則請求可能不會被處理,並且會被拒絕授權
  • 處理器不應形成遞歸循環
    • 在上面的示例中,我們的鏈中沒有循環:UsernamePasswordProcessor -> OAuthProcessor. 但是,如果我們明確地將 UsernamePasswordProcessor 設置為 OAuthProcessor 的下一個處理器,那麼我們就會在鏈中形成一個循環:UsernamePasswordProcessor -> OAuthProcessor -> UsernamePasswordProcessor. 通過在構造函數中獲取下一個處理器可以幫助解決這個問題
  • 鏈中的只有一個處理器處理給定的命令
    • 在上面的示例中,如果傳入的命令包含 OAuthTokenProvider 的實例,則只有 OAuthProcessor 會處理該命令

5. 實際應用

在Java世界中,我們每天都受益於責任鏈模式。其中一個經典的例子是Java中的Servlet過濾器,它們允許多個過濾器處理HTTP請求。儘管在這種情況中,每個過濾器調用鏈,而不是下一個過濾器。

以下代碼片段可以幫助更好地理解Servlet過濾器中該模式:

public class CustomFilter implements Filter {

    public void doFilter(
      ServletRequest request,
      ServletResponse response,
      FilterChain chain)
      throws IOException, ServletException {

        // process the request

        // pass the request (i.e. the command) along the filter chain
        chain.doFilter(request, response);
    }
}

如代碼片段所示,我們需要調用 FilterChaindoFilter 方法,以便將請求傳遞給鏈中的下一個處理器。

6. 缺點

現在我們已經瞭解了責任鏈模式的有趣之處,接下來讓我們考慮一些缺點:

  • 通常,它容易中斷:
    • 如果一個處理器未能調用下一個處理器,則命令將被丟棄
    • 如果一個處理器調用了錯誤的處理器,可能會導致循環
  • 它可能會創建深層堆棧跟蹤,從而影響性能
  • 它可能導致處理器之間出現重複代碼,從而增加維護成本

7. 結論

在本文中,我們通過使用一個鏈條來授權傳入的身份驗證請求,探討了職責鏈模式及其優勢和劣勢。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.