Responsibility chain model
definition
Chain of responsibility: multiple objects have the opportunity to process the request, so as to avoid the coupling relationship between the sender and receiver of the request. Connect the object into a chain and pass the request along the chain until an object is processed.
Is a mode of processing a request, which gives multiple processors the opportunity to process the request until one of them succeeds. The responsibility chain model links multiple processors into a chain, and then allows requests to pass on the chain.
Take a chestnut
For example, if a student asks for leave for less than or equal to 2 days, the head teacher can approve it; Less than or equal to 7 days, the Dean can approve; Less than or equal to 10 days, the president may approve. In other cases, it shall not be approved.
The responsibility chain model is used to design the approval process. Each auditor only cares about the request within his own responsibility and handles it. For those beyond their own responsibility, they will be thrown to the next reviewer for processing. In this way, when adding reviewers in the future, there is no need to change the existing logic.
advantage
1. Reduce coupling. It decouples the sender and receiver of the request;
2. Simplifies objects. So that the object does not need to know the structure of the chain;
3. Enhance the flexibility of assigning responsibilities to objects. By changing the members in the chain or transferring their order, it is allowed to dynamically add or delete responsibilities;
4. It is convenient to add new request processing classes.
shortcoming
There is no guarantee that the request will be received
Scope of application
1. Multiple objects can process a request, but which object handles the request is automatically determined at run time;
2. You can dynamically specify a group of objects to process requests, or add new processors;
3. You need to submit a request to one of multiple processors without explicitly specifying the request processor.
code implementation
Chestnuts on which students ask for leave:
If students ask for leave for less than or equal to 2 days, the head teacher can approve it; Less than or equal to 7 days, the Dean can approve; Less than or equal to 10 days, the president may approve. In other cases, it shall not be approved.
type Teacher interface { HaveRight(day int) bool HandleApproveRequest(name string, day int) bool } type RequestChain struct { Teacher approver *RequestChain } func (r *RequestChain) SetApprover(m *RequestChain) { r.approver = m } func (r *RequestChain) HandleApproveRequest(name string, day int) bool { if r.Teacher.HaveRight(day) { return r.Teacher.HandleApproveRequest(name, day) } if r.approver != nil { return r.approver.HandleApproveRequest(name, day) } fmt.Println("It took too long to ask for leave, so it was not approved") return false } func (r *RequestChain) HaveRight(day int) bool { return true } type HeadTeacher struct{} func NewHeadTeacherChain() *RequestChain { return &RequestChain{ Teacher: &HeadTeacher{}, } } func (*HeadTeacher) HaveRight(day int) bool { return day <= 2 } func (*HeadTeacher) HandleApproveRequest(name string, day int) bool { fmt.Println(fmt.Sprintf("Head teacher, approved%s Leave application for,Leave days%d", name, day)) return true } type DepTeacher struct{} func NewDepManagerChain() *RequestChain { return &RequestChain{ Teacher: &DepTeacher{}, } } func (*DepTeacher) HaveRight(day int) bool { return day <= 7 } func (*DepTeacher) HandleApproveRequest(name string, day int) bool { fmt.Println(fmt.Sprintf("Dean, approved%s Leave application for,Leave days%d", name, day)) return true } type DeanTeacher struct{} func NewDeanTeacherChain() *RequestChain { return &RequestChain{ Teacher: &DeanTeacher{}, } } func (*DeanTeacher) HaveRight(day int) bool { return day <= 10 } func (*DeanTeacher) HandleApproveRequest(name string, day int) bool { fmt.Println(fmt.Sprintf("Dean, approved%s Leave application for,Leave days%d", name, day)) return true }
Test code
func TestApproveChain(t *testing.T) { c1 := NewHeadTeacherChain() c2 := NewDepManagerChain() c3 := NewDeanTeacherChain() c1.SetApprover(c2) c2.SetApprover(c3) var c Teacher = c1 assert.Equal(t, true, c.HandleApproveRequest("Xiao Ming", 3)) assert.Equal(t, true, c.HandleApproveRequest("Xiao Hong", 2)) assert.Equal(t, false, c.HandleApproveRequest("Bruce Lee", 30)) }
output
The dean of the Department approved Xiao Ming's application for leave,Leave days 3 The head teacher approved Xiao Hong's application for leave,Leave days 2 It took too long to ask for leave, so it was not approved
Responsibility chain mode vs. decoration mode
The chain of responsibility is very similar to the decoration model. Both rely on recursive composition to pass the operation to be performed to a series of objects. Let's look at the differences between the two.
1. The managers of the responsibility chain can perform all operations independently of each other, and can stop transmitting requests at any time.
2. Decoration mode can extend objects, but it cannot interrupt the delivery of requests.
reference resources
[code in text] https://github.com/boilingfrog/design-pattern-learning/tree/master/ Responsibility chain model
[big talk design mode] https://book.douban.com/subject/2334288/
[geek time] https://time.geekbang.org/column/intro/100039001
[detailed explanation of responsibility chain model (responsibility chain model)] http://c.biancheng.net/view/1383.html
[responsibility chain model] https://boilingfrog.github.io/2021/11/22/ Using go to implement the responsibility chain model/