REBAJA de primavera
Chain of Responsibility

Chain of Responsibility en Go

Chain of Responsibility es un patrón de diseño de comportamiento que permite pasar solicitudes a lo largo de la cadena de manejadores potenciales hasta que uno de ellos gestiona la solicitud.

El patrón permite que varios objetos gestionen la solicitud sin acoplar la clase emisora a las clases concretas de los receptores. La cadena puede componerse dinámicamente durante el tiempo de ejecución con cualquier manejador que siga una interfaz manejadora estándar.

Ejemplo conceptual

Veamos el patrón Chain of Responsibility con el caso de una aplicación de hospital. Un hospital puede tener varios departamentos, como:

  • Recepción
  • Consulta
  • Sala de curas
  • Caja

Cuando llega un paciente, primero pasa por recepción, después por la consulta del médico y después por la sala de curas, y por último por la caja (etcétera). El paciente pasa por una cadena de departamentos y cada uno de ellos envía al paciente un poco más allá en la cadena, una vez que se complete su función.

El patrón se aplica cuando hay varios candidatos para procesar la misma solicitud. Cuando no quieres que el cliente elija el receptor ya que varios objetos pueden gestionar la solicitud. Además, quieres desacoplar el cliente de los receptores. El cliente solo necesita conocer el primer elemento de la cadena.

Al igual que en el ejemplo del hospital, el paciente pasa primero por la recepción. Después, en base al estado del paciente, desde recepción lo envían al siguiente manejador de la cadena.

department.go: Interfaz manejador

package main

type Department interface {
	execute(*Patient)
	setNext(Department)
}

reception.go: Manipulador concreto

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: Manipulador concreto

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: Manipulador concreto

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: Manipulador concreto

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

package main

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

main.go: Código cliente

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: Resultado de la ejecución

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

Chain of Responsibility en otros lenguajes

Chain of Responsibility en C# Chain of Responsibility en C++ Chain of Responsibility en Java Chain of Responsibility en PHP Chain of Responsibility en Python Chain of Responsibility en Ruby Chain of Responsibility en Rust Chain of Responsibility en Swift Chain of Responsibility en TypeScript