Chain of Responsibility Pattern
Chain of Responsibility Pattern creates a chain of receiver objects for a request. This pattern decouples the sender and receiver of the request based on the type of request. This type of design pattern belongs to behavioral patterns.
The Chain of Responsibility pattern connects multiple handlers (processing objects) in a chain structure, allowing the request to be passed along the chain until a handler processes it.
The Chain of Responsibility pattern allows multiple objects to have the opportunity to handle the request, thereby avoiding coupling between the sender and receiver of the request. These objects are connected into a chain, and the request is passed along the chain.
Introduction
intent
Allows the request to be passed along the chain of handlers until the request is handled.
Main problems solved
- Decouples the sender and receiver of the request, allowing multiple objects to have the possibility of receiving the request, while the sender does not need to know which object will handle it.
Use Case
- When there are multiple objects that can handle a request, and which specific object handles it is determined at runtime.
- When you need to submit a request to one of multiple objects without explicitly specifying the receiver.
Implementation Approach
- Define handler interface: All handlers must implement the same interface.
- Create concrete handlers: Concrete classes implementing the interface, containing request handling logic and a reference to the next handler in the chain.
Key code
- Handler interface: Define a method for handling requests.
- ConcreteHandler class: Implements the Handler interface, containing request handling logic and a reference to the next handler.
Application example
- Hot Potato: Passing behavior in a game, until the music stops.
- Event Bubbling: In JavaScript, events start from the most specific element and propagate upward level by level.
- Web serverExamples include Apache Tomcat handling character encoding, Struts2 interceptors, and Servlet Filters.
Advantages
- Reduce Coupling: Decouple the sender and receiver.
- Simplify Objects: The object does not need to know the structure of the chain.
- Flexibility: Dynamically add or remove responsibilities by changing the members or order of the chain.
- Easy to Extend: It is convenient to add new request handler classes.
Disadvantages
- Request not handled: There is no guarantee that the request will be received by a handler in the chain.
- Performance Impact: May affect system performance, and debugging is difficult, may lead to circular calls.
- Difficult to Observe: Runtime characteristics are not obvious, which may hinder debugging.
Usage suggestions
- When handling a request, if there are multiple potential handlers, consider using the Chain of Responsibility pattern.
- Ensure that each handler in the chain clearly knows how to pass the request to the next link in the chain.
Notes
- In Java Web development, the Chain of Responsibility pattern is widely used, such as filter chains, interceptors, etc.
Structure
It mainly involves the following core roles:
Abstract Handler:
- Define an interface for handling requests, usually containing a method to handle the request (such as
handleRequest) and a reference to the next handler (successor).
- Define an interface for handling requests, usually containing a method to handle the request (such as
Concrete Handler:
- Implements the abstract handler interface and is responsible for handling requests. If it can handle the request, it handles it directly; otherwise, it passes the request to the next handler.
Client:
- Create handler objects and connect them into a chain of responsibility. Usually, the client only needs to send the request to the first handler in the chain, without needing to care about the specific processing of the request.
Implementation
We create an abstract classAbstractLogger, with detailed log levels. Then we create three types of loggers, all extendingAbstractLogger. Each logger checks whether the message's level belongs to its own level; if so, it prints it accordingly; otherwise, it does not print and passes the message to the next logger.
Step 1
Create an abstract logger class.
AbstractLogger.java
Step 2
Create entity classes that extend the logger class.
ConsoleLogger.java
ErrorLogger.java
FileLogger.java
Step 3
Create different types of loggers. Assign them different error levels, and set the next logger in each logger. The next logger in each logger represents part of the chain.
ChainPatternDemo.java
Step 4
Execute the program, output results:
Standard Console::Logger: This is an information. File::Logger: This is a debug level information. Standard Console::Logger: This is a debug level information. Error Console::Logger: This is an error information. File::Logger: This is an error information. Standard Console::Logger: This is an error information.other extensions