行为型 - 4. 责任链模式

116 阅读2分钟

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)

}