責任鏈模式是一種行為型設計模式。在這種模式中,會為請求建立一條由多個Handler組成的鏈路。每一個進入的請求,都會經過這條鏈路。這條鏈路上的Handler可以選擇如下操作:
- 處理請求或跳過處理
- 決定是否將請求傳給這條鏈路上的下一個Handler
下面是責任鏈模式的用例圖:
關於責任鏈模式的用途最好還是用個案例來說明下。
以醫院為例。在一個醫院中會有如下職責成員:
- 掛號處
- 醫生
- 收銀處
- 藥房
當病人來醫院看病時,他會先去掛號處掛號,然後找醫生看病,看完病後去收銀處繳費,最後去藥房拿藥。在這個過程中,病人需要經過一個由四個職責部門組成的鏈條。病人在一個職責部門的事務結束後才能進入後續的職責部門,在這個過程中我們可以清晰地看到一條職責鏈。
現在可以說說責任鏈模式的適用場景了:
- 當一個請求需要經過多個環節的處理時;
- 因為有多個物件可以處理某個請求,但我們並不想讓客戶端選擇處理請求的物件,同時我們還想將客戶端和處理器解耦,此時我們可以選擇職責鏈模式:客戶端只需要和職責鏈中的第一個處理器接觸就可以了。
下面是病人到醫院看病這個例項的類圖:
實現程式碼如下:
department.go
type department interface {
execute(*patient)
setNext(department)
}
medical.go
import "fmt" 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")
p.medicineDone = true
m.next.execute(p)
} func (m *medical) setNext(next department) {
m.next = next
}
cashier.go
import "fmt" 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")
c.next.execute(p)
} func (c *cashier) setNext(next department) {
c.next = next
}
doctor.go
import "fmt" 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")
p.doctorCheckUpDone = true
d.next.execute(p)
} func (d *doctor) setNext(next department) {
d.next = next
}
reception.go
import "fmt" 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")
p.registrationDone = true
r.next.execute(p)
} func (r *reception) setNext(next department) {
r.next = next
}
patient.go
type patient struct {
name string
registrationDone bool
doctorCheckUpDone bool
medicineDone bool
paymentDone bool
}
main.go
func main() { medical := &medical{} //Set next for cashier department
cashier := &cashier{}
cashier.setNext(medical)
//Set next for doctor department
doctor := &doctor{}
doctor.setNext(cashier)
//Set next for reception department
reception := &reception{}
reception.setNext(doctor) patient := &patient{name: "abc"}
//Patient visiting
reception.execute(patient)
}
執行結果如下:
Reception registering patient
Doctor checking patient
Cashier getting money from patient patient
Medical giving medicine to patient
程式碼已上傳至GitHub:zhyea / go-patterns / Chain of Responsibility Design Pattern
END!