Basic introduction
The chain of Responsibilities Pattern allows you to send the request along the handler chain. After the handler receives the request, he can process it or pass it to the next handler.
Pattern structure
Handler (Abstract handler): defines an interface for processing requests, and aggregates an object (successor) of its own type. Subclass can pass the request on by setting the successor
Concrete handler: after receiving the request, the specific handler can process the request or pass it to the successor.
Request: define some attributes to represent a request
Examples
Company procurement approval process:
- Amount < = 5000 to be approved by team leader
- 5000 < amount < = 10000 to be approved by manager
- Amount > 10000 to be approved by the boss
Request with id and price fields
public class PurchaseRequest { private int id; private float price; public PurchaseRequest(int id, float price) { this.id = id; this.price = price; } public int getId() { return id; } public float getPrice() { return price; } }
Abstract processor
public abstract class Approver { protected String name; protected Approver approver; public Approver(String name) { this.name = name; } public void setApprover(Approver approver) { this.approver = approver; } /** * Process request * @param request */ public abstract void processRequest(PurchaseRequest request); }
Specific handler
public class TeamLeader extends Approver { public TeamLeader(String name) { super(name); } @Override public void processRequest(PurchaseRequest request) { if (request.getPrice() <= 5000) { System.out.println(name + "Approved" + request.getId() + "Request, price is" + request.getPrice()); } else { approver.processRequest(request); } } }
public class Manager extends Approver { public Manager(String name) { super(name); } @Override public void processRequest(PurchaseRequest request) { if (request.getPrice() > 5000 && request.getPrice() <= 10000) { System.out.println(name + "Approved" + request.getId() + "Request, price is" + request.getPrice()); } else { approver.processRequest(request); } } }
public class Boss extends Approver { public Boss(String name) { super(name); } @Override public void processRequest(PurchaseRequest request) { if (request.getPrice() > 10000) { System.out.println(name + "Approved" + request.getId() + "Request, price is" + request.getPrice()); } else { approver.processRequest(request); } } }
Test class
public class Client { @Test public void test(){ PurchaseRequest request = new PurchaseRequest(1, 5000); TeamLeader teamLeader = new TeamLeader("Group leader Li"); Manager manager = new Manager("Manager Zhang"); Boss boss = new Boss("Boss Wang"); teamLeader.setApprover(manager); manager.setApprover(boss); boss.setApprover(teamLeader); manager.processRequest(request); boss.processRequest(request); } }
Operation results
Team leader Li approved request No.1 with a price of 5000.0 Team leader Li approved request No.1 with a price of 5000.0
pattern analysis
advantage
- Reduce coupling. It decouples the sender and receiver of the request
- Simplified objects. So that the object does not need to know the structure of the chain
- Increase flexibility in assigning responsibilities to objects. Allow dynamic addition or deletion of responsibilities by changing the members of the chain or moving their order
- It is convenient to add new request processing classes
shortcoming
- There is no guarantee that the request will be received
- The system performance will be affected to some extent, and it is not convenient to debug the code, which may cause circular calls
- It may not be easy to observe the characteristics of the running time, which hinders debugging
Applicable scenarios
- There are multiple objects that can handle the same request. The runtime automatically determines which object handles the request
- Submit a request to one of multiple objects without explicitly specifying the recipient
- A set of objects can be dynamically specified to process requests