Hourra ! La version française est enfin sortie ! Laissez-nous un message svp, si vous voulez nous faire part de vos commentaires ou signaler une erreur.
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: Handler concret

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

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