Viva! A versão em Português Brasileiro finalmente foi lançada! Por favor, envie-nos uma mensagem se você quer compartilhar sua opinião ou relatar um erro.
Chain of Responsibility

Chain of Responsibility em Go

O Chain of Responsibility é um padrão de projeto comportamental que permite passar a solicitação ao longo da cadeia de handlers em potencial até que um deles lide com a solicitação.

O padrão permite que vários objetos tratem a solicitação sem acoplar a classe remetente às classes concretas dos destinatários. A cadeia pode ser composta dinamicamente em tempo de execução com qualquer handler que siga uma interface de handler padrão.

Exemplo conceitual

Vejamos o padrão Chain of Responsibility com o caso de um aplicativo de hospital. Um hospital pode ter vários departamentos, como:

  • Recepção
  • Médico
  • Sala de remédios
  • Caixa

Sempre que chega algum paciente, ele vai primeiro para a Recepção, depois para o Médico, depois para a Sala de Remédios e depois para o Caixa (e assim por diante). O paciente está sendo enviado por uma cadeia de departamentos, onde cada departamento o envia mais adiante na cadeia, uma vez que sua função esteja concluída.

O padrão é aplicável quando há vários candidatos para processar a mesma solicitação. Quando você não quer que o cliente escolha o receptor, pois vários objetos podem lidar com a solicitação. Além disso, você deseja desacoplar o cliente dos receptores. O cliente só precisa conhecer o primeiro elemento da cadeia.

Como no exemplo do hospital, o paciente primeiro vai até a recepção. Então, com base no status atual do paciente, a recepção envia para o próximo handler da cadeia.

department.go: Interface do handler

package main

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

reception.go: Handler 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: Handler 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: Handler 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: Handler 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: Handler concreto

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: Resultados da execução

Reception registering patient
Doctor checking patient
Medical giving medicine to patient
Cashier getting money from patient patient
Baseado em: Golang By Example

Chain of Responsibility em outras linguagens

Padrões de Projeto: Chain of Responsibility em Java Padrões de Projeto: Chain of Responsibility em C# Padrões de Projeto: Chain of Responsibility em C++ Padrões de Projeto: Chain of Responsibility em PHP Padrões de Projeto: Chain of Responsibility em Python Padrões de Projeto: Chain of Responsibility em Ruby Padrões de Projeto: Chain of Responsibility em Swift Padrões de Projeto: Chain of Responsibility em TypeScript