Hooray! After 3 years of work, I've finally released the ebook on design patterns! Check it out »
Chain of Responsibility

Chain of Responsibility in Go

Chain of Responsibility is behavioral design pattern that allows passing request along the chain of potential handlers until one of them handles request.

The pattern allows multiple objects to handle the request without coupling sender class to the concrete classes of the receivers. The chain can be composed dynamically at runtime with any handler that follows a standard handler interface.

Conceptual Example

Let’s look at the Chain of Responsibility pattern with the case of a hospital app. A hospital could have multiple departments such as:

  • Reception
  • Doctor
  • Medicine room
  • Cashier

Whenever any patient arrives, they first get to Reception, then to Doctor, then to Medicine Room, and then to Cashier (and so on). The patient is being sent through a chain of departments, where each department sends the patient further down the chain once their function is completed.

The pattern is applicable when there are multiple candidates to process the same request. When you don’t want the client to choose the receiver as multiple objects can handle the request. Also, you want to decouple the client from receivers. The client only needs to know the first element in the chain.

As in the example of the hospital, a patient first goes to the reception. Then, based upon a patient’s current status, reception sends up to the next handler in the chain.

department.go: Handler interface

package main

type department interface {
	execute(*patient)
	setNext(department)
}

reception.go: Concrete handler

package main

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
}

doctor.go: Concrete handler

package main

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
}

medical.go: Concrete handler

package main

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: Concrete handler

package main

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")
}

func (c *cashier) setNext(next department) {
	c.next = next
}

patient.go: Concrete handler

package main

type patient struct {
	name              string
	registrationDone  bool
	doctorCheckUpDone bool
	medicineDone      bool
	paymentDone       bool
}

main.go: Client code

package main

func main() {

	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)
}

output.txt: Execution result

Reception registering patient
Doctor checking patient
Medical giving medicine to patient
Cashier getting money from patient patient

Chain of Responsibility in Other Languages

Design Patterns: Chain of Responsibility in Java Design Patterns: Chain of Responsibility in C# Design Patterns: Chain of Responsibility in C++ Design Patterns: Chain of Responsibility in PHP Design Patterns: Chain of Responsibility in Python Design Patterns: Chain of Responsibility in Ruby Design Patterns: Chain of Responsibility in Swift Design Patterns: Chain of Responsibility in TypeScript