定義
責任鏈模式是一種行為型設計模式,用于在對象間建立一條處理請求的鏈。它允許多個對象有機會處理請求,從而減少請求的發送者和接收者之間的耦合。在責任鏈模式中,每個接收者包含對另一個接收者的引用,形成一條鏈。如果一個對象不能處理請求,它會將請求傳遞給鏈中的下一個對象,直至鏈的末端。
責任鏈模式由多個處理器(或接收者)組成,每個處理器決定自己是否處理請求或將其傳遞給鏈上的下一個處理器。這種模式實現了發送者和接收者之間的解耦,同時允許動態地調整鏈中的處理器。
責任鏈模式主要包含以下兩個角色:
- 處理器(Handler):
- 定義了處理請求的接口或抽象類,并通常持有對下一個處理器的引用。在其子類中,它可以選擇處理請求或將請求傳遞給鏈上的下一個對象。
- 具體處理器(Concrete Handler):
- 實現處理器接口的具體類。每個具體處理器決定它是否要處理請求,如果不處理,則將請求傳遞給鏈中的下一個對象。
解決的問題
- 請求的發送者和接收者解耦:
- 在沒有責任鏈模式的情況下,請求的發送者需要知道哪個接收者能夠處理該請求,并直接調用相應的處理方法。責任鏈模式使得請求的發送者不需要直接與具體的接收者交互,從而解耦了發送者和接收者。
- 動態處理請求:
- 責任鏈模式允許動態地重新組織和分配責任鏈上的處理者。這意味著可以在運行時改變請求的處理順序或者增加新的處理者。
- 簡化對象間的連接:
- 通過責任鏈,可以減少對象間復雜的條件語句。在責任鏈模式中,請求沿著鏈傳遞,直到被處理。這避免了顯式的多重條件判斷。
- 增加處理者的靈活性:
- 責任鏈模式讓每個處理者都有機會處理請求。處理者可以決定是否處理請求,或者將請求傳遞給鏈上的下一個對象。
- 分布式責任:
- 責任鏈模式允許多個對象處理請求,而不是只有一個對象負責所有的情況。這種分布式責任有助于代碼的復用和擴展。
使用場景
- 多個對象可以處理同一個請求,但具體的處理者在運行時才確定:
- 當一個請求可能由多個不同的對象處理,但是具體由哪個對象處理在運行時才決定時,責任鏈模式是理想的解決方案。
- 請求的發送者不需要知道是誰處理了請求:
- 如果請求的發送者不需要知道請求最終由哪個對象處理,責任鏈模式可以將請求的發送和處理解耦。
- 動態指定一組對象處理請求:
- 當需要動態地指定一系列對象來處理請求時,責任鏈模式提供了一種靈活的方法來組織這些對象。
- 實現不同方式的請求處理:
- 在有多種處理方式,并且希望根據請求的類型或條件以不同的方式處理時,責任鏈模式能夠提供足夠的靈活性。
示例代碼1-日志處理器
// 抽象處理器類
public abstract class Logger {public static int INFO = 1;public static int DEBUG = 2;public static int ERROR = 3;protected int level;protected Logger nextLogger;public void setNextLogger(Logger nextLogger) {this.nextLogger = nextLogger;}public void logMessage(int level, String message) {if (this.level <= level) {write(message);}if (nextLogger != null) {nextLogger.logMessage(level, message);}}abstract protected void write(String message);
}// 具體處理器實現
class ConsoleLogger extends Logger {public ConsoleLogger(int level) {this.level = level;}@Overrideprotected void write(String message) { System.out.println("Standard Console::Logger: " + message);}
}// 客戶端使用責任鏈
public class ChainPatternDemo {private static Logger getChainOfLoggers() {Logger errorLogger = new ErrorLogger(Logger.ERROR);Logger fileLogger = new FileLogger(Logger.DEBUG);Logger consoleLogger = new ConsoleLogger(Logger.INFO);errorLogger.setNextLogger(fileLogger);fileLogger.setNextLogger(consoleLogger);return errorLogger;}public static void main(String[] args) {Logger loggerChain = getChainOfLoggers();loggerChain.logMessage(Logger.INFO, "This is an information.");loggerChain.logMessage(Logger.DEBUG, "This is a debug level information.");loggerChain.logMessage(Logger.ERROR, "This is an error information.");}
}
示例代碼2-審批流程
// 抽象處理器
abstract class Approver {protected Approver successor;public void setSuccessor(Approver successor) {this.successor = successor;}public abstract void processRequest(PurchaseRequest request);
}// 具體處理器:經理
class Manager extends Approver {public void processRequest(PurchaseRequest request) {if (request.getAmount() < 1000) {System.out.println("Manager will approve the request of " + request.getAmount());} else if (successor != null) {successor.processRequest(request);}}
}// 具體處理器:總監
class Director extends Approver {public void processRequest(PurchaseRequest request) {if (request.getAmount() < 5000) {System.out.println("Director will approve the request of " + request.getAmount());} else if (successor != null) {successor.processRequest(request);}}
}// 具體處理器:CEO
class CEO extends Approver {public void processRequest(PurchaseRequest request) {if (request.getAmount() < 10000) {System.out.println("CEO will approve the request of " + request.getAmount());} else {System.out.println("Request of " + request.getAmount() + " needs a board meeting!");}}
}// 請求類
class PurchaseRequest {private double amount;public PurchaseRequest(double amount) {this.amount = amount;}public double getAmount() {return amount;}
}// 客戶端代碼
public class ChainOfResponsibilityDemo {public static void main(String[] args) {Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();manager.setSuccessor(director);director.setSuccessor(ceo);manager.processRequest(new PurchaseRequest(500));manager.processRequest(new PurchaseRequest(1500));manager.processRequest(new PurchaseRequest(5500));}
}
主要符合的設計原則
- 開閉原則(Open-Closed Principle):
- 責任鏈模式允許在不修改現有代碼的情況下添加新的處理器。你可以添加新的處理類來擴展系統的功能,而無需修改現有的處理鏈或客戶端代碼。因此,系統對擴展是開放的,但對修改是封閉的。
- 單一職責原則(Single Responsibility Principle):
- 在責任鏈模式中,每個處理器只負責處理特定類型的請求。這符合單一職責原則,因為每個處理器類只有一個理由發生變化——處理其特定的請求。
- 里氏替換原則(Liskov Substitution Principle):
- 責任鏈中的處理器通常遵循相同的接口。這意味著處理器的任何子類都可以替換其父類,而不影響系統的行為。
在JDK中的應用
- java.util.logging.Logger:
- 在
java.util.logging
包中,Logger
類使用責任鏈模式。日志消息可以在一個日志處理鏈中傳遞,每個處理器(如ConsoleHandler
,FileHandler
)決定是否處理日志消息,并將消息傳遞到鏈中的下一個處理器。
- 在
- Java Servlet Filters:
- 在Java Servlet API中,過濾器(Filter)使用責任鏈模式。請求和響應在多個過濾器之間傳遞,每個過濾器可以獨立地處理請求或響應,或將其傳遞給鏈中的下一個過濾器。
- javax.servlet.FilterChain:
FilterChain
是Servlet API的一部分,它允許多個過濾器按順序處理HTTP請求和響應。每個過濾器在鏈中都有機會處理請求和響應,或將其傳遞給鏈上的下一個過濾器。
在Spring中的應用
- Spring Security的過濾器鏈:
- 在Spring Security中,安全過濾器鏈是責任鏈模式的一個顯著例子。請求通過一系列的安全過濾器,每個過濾器執行特定的安全檢查(如認證、授權等)。這些過濾器可以自定義和配置,形成一個處理安全的責任鏈。
- Spring Web的攔截器:
- 在Spring MVC中,攔截器(Interceptor)提供了一種在處理HTTP請求時插入自定義邏輯的機制。攔截器可以形成一個攔截器鏈,每個攔截器按順序執行,處理請求或響應,或將控制權傳遞給鏈中的下一個攔截器。
- Spring AOP的通知鏈:
- 在Spring的面向切面編程(AOP)中,通知(Advice)可以被看作是責任鏈的一部分。不同的通知(如前置通知、后置通知、環繞通知等)可以按順序應用于方法調用,形成一個通知鏈。