1. Qu'est-ce que le modèle Décorateur?

Le modèle décorateur est un modèle de conception structurel qui permet d'ajouter dynamiquement des fonctionnalités supplémentaires à un objet sans modifier le code de l'objet. Il y parvient en enveloppant l'objet dans une classe décoratrice, offrant la possibilité d'ajouter, de modifier ou d'améliorer le comportement de l'objet à l'exécution.

2. Caractéristiques et avantages du modèle Décorateur

Les caractéristiques et avantages du modèle décorateur comprennent:

  • Extension dynamique des fonctionnalités d'un objet sans modifier son code.
  • Conformité au principe ouvert/fermé, permettant l'ajout et la suppression dynamiques des décorateurs.
  • Possibilité de combiner plusieurs décorateurs pour obtenir des extensions de fonctionnalités imbriquées.
  • Indépendance des décorateurs vis-à-vis de la manière dont l'objet est décoré, permettant des modifications indépendantes.

3. Exemples d'applications pratiques du modèle Décorateur

Le modèle décorateur a de nombreuses applications pratiques dans le développement logiciel, telles que:

  • Ajout dynamique de fonctionnalités de journalisation
  • Ajout dynamique de fonctionnalités de mise en cache
  • Validation dynamique des données

4. Implémentation du modèle Décorateur en Golang

4.1. Diagramme de classe UML

Modèle Décorateur en Golang

4.2. Introduction de l'exemple

Dans l'exemple, nous avons une interface Component et une classe ConcreteComponent qui implémente la méthode Operation de l'interface Component.

Ensuite, nous avons une classe Decorator, qui implémente également l'interface Component. La classe Decorator possède une variable membre de type Component.

Les classes ConcreteDecoratorA et ConcreteDecoratorB héritent de la classe Decorator et implémentent des fonctionnalités supplémentaires en remplaçant la méthode Operation.

4.3. Étape 1 de l'implémentation : Définir l'interface et la classe d'implémentation

type Component interface {
	Operation() string
}

type ConcreteComponent struct {}

func (c *ConcreteComponent) Operation() string {
	return "opération spécifique du composant"
}

4.4. Étape 2 de l'implémentation : Définir le décorateur

type Decorator struct {
	component Component
}

func (d *Decorator) Operation() string {
	return d.component.Operation()
}

4.5. Étape 3 de l'implémentation : Implémentation du décorateur

type ConcreteDecoratorA struct {
	Decorator
	addedState string
}

func (c *ConcreteDecoratorA) Operation() string {
	c.addedState = "Nouvel état"
	return c.addedState + " " + c.component.Operation()
}

type ConcreteDecoratorB struct {
	Decorator 
}

func (c *ConcreteDecoratorB) Operation() string {
	return "opération spécifique du décorateur B " + c.component.Operation()
}

4.6. Étape 4 de l'implémentation : Utilisation du décorateur

func main() {
	component := &ConcreteComponent{}

	decoratorA := &ConcreteDecoratorA{}
	decoratorA.component = component

	decoratorB := &ConcreteDecoratorB{}
	decoratorB.component = decoratorA

	result := decoratorB.Operation()
	fmt.Println(result)
}

5. Comparaison du modèle Décorateur avec d'autres modèles de conception

5.1. Comparaison avec l'héritage

Comparé à l'héritage, le modèle décorateur peut ajouter dynamiquement des fonctionnalités sans modifier le code existant, tandis que l'héritage est statique et doit être déterminé à l'heure de la compilation.

5.2. Comparaison avec le modèle de proxy statique

Le modèle décorateur et le modèle de proxy statique peuvent tous deux étendre des fonctionnalités, mais le modèle décorateur est plus flexible et permet l'ajout et la suppression dynamiques de fonctionnalités.

5.3. Comparaison avec le modèle de proxy dynamique

Le modèle décorateur et le modèle de proxy dynamique peuvent tous deux étendre les fonctionnalités des objets à l'exécution. Cependant, le modèle décorateur décore un seul objet, tandis que le modèle de proxy dynamique implique un accès indirect entre l'objet proxy et l'objet cible.