SOLDES de printemps
Chaîne de responsabilité

Chaîne de responsabilité en Go

La Chaîne de responsabilité est un patron de conception comportemental qui permet de faire circuler une demande tout au long d’une chaîne de handlers, jusqu’à ce que l’un d’entre eux la traite.

Ce patron permet à plusieurs objets de traiter une demande sans coupler la classe du demandeur aux classes concrètes des récepteurs. La chaîne peut être assemblée dynamiquement à l’exécution à l’aide de tout handler implémentant l’interface standard des handlers.

Exemple conceptuel

Regardons un peu la chaîne de responsabilité utilisée dans l’application d’un hôpital. Un hôpital peut être composé de plusieurs départements comme :

  • La réception
  • Les docteurs
  • La salle de soins
  • La caisse

Lorsqu’un patient arrive, il se rend d’abord à la réception, consulte ensuite un docteur, passe du temps dans la salle de soins et finit par aller à la caisse pour payer, etc. Le patient est envoyé à travers une chaîne de départements, et chacun d’entre eux expédie le patient plus loin dans la chaîne une fois qu’il a rempli son rôle.

Ce patron est utilisable lorsque plusieurs candidats vont effectuer la même demande. Il se montre très utile lorsque vous voulez empêcher le client de choisir son récepteur, car plusieurs objets peuvent gérer la demande. Il est également pratique si vous voulez découpler le client des récepteurs : le client n’aura besoin que de connaître le premier élément de la chaîne.

Si l’on reprend l’exemple de l’hôpital, le patient arrive d’abord à la réception. Ensuite, en fonction de son état, la réception l’envoie au prochain handler de la chaîne.

department.go: Interface handler

package main

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

reception.go: Handler concret

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 concret

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 concret

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 concret

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: Code client

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: Résultat de l’exécution

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

Chaîne de responsabilité dans les autres langues

Chaîne de responsabilité en C# Chaîne de responsabilité en C++ Chaîne de responsabilité en Java Chaîne de responsabilité en PHP Chaîne de responsabilité en Python Chaîne de responsabilité en Ruby Chaîne de responsabilité en Rust Chaîne de responsabilité en Swift Chaîne de responsabilité en TypeScript