1. 责任链模式的原理
责任链模式,英文是 Chain Of Responsibility Design Pattern,将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍,不存在中途终止的情况。
2. 责任链模式的实现
type patient struct {
name string
registrationDone bool
doctorCheckUpDone bool
medicineDone bool
paymentDone bool
}
type department interface {
execute(*patient)
setNext(department)
}
type reception struct {
next department
}
func (r *reception) execute(p *patient) {
if p.registrationDone {
fmt.Println("Patient registration already done")
r.next.execute(p)
return
}
fmt.Println("Reception registering patient")
r.next.execute(p)
p.registrationDone = true
}
func (r *reception) setNext(next department) {
r.next = next
}
type doctor struct {
next department
}
func (d *doctor) execute(p *patient) {
if p.doctorCheckUpDone {
fmt.Println("Doctor checkup already done")
d.next.execute(p)
return
}
fmt.Println("Doctor checking patient")
d.next.execute(p)
p.doctorCheckUpDone = true
}
func (d *doctor) setNext(next department) {
d.next = next
}
type medical struct {
next department
}
func (m *medical) execute(p *patient) {
if p.medicineDone {
fmt.Println("Medicine already given to patient")
m.next.execute(p)
return
}
fmt.Println("Medical giving medicine to patient")
m.next.execute(p)
}
func (m *medical) setNext(next department) {
m.next = next
}
type cashier struct {
next department
}
func (c *cashier) execute(p *patient) {
if p.paymentDone {
fmt.Println("Payment Done")
}
fmt.Println("Cashier getting money from patient patient")
}
func (c *cashier) setNext(next department) {
c.next = next
}
// 客户端使用代码
func TestPatient(t *testing.T) {
cashier := &cashier{}
//Set next for medical department
medical := &medical{}
medical.setNext(cashier)
//Set next for doctor department
doctor := &doctor{}
doctor.setNext(medical)
//Set next for reception department
reception := &reception{}
reception.setNext(doctor)
patient := &patient{name: "abc"}
//Patient visiting
reception.execute(patient)
}