Le modèle de décorateur en Java

1. Vue d'ensemble

Un modèle Decorator peut être utilisé pour associer des responsabilités supplémentaires à un objet de manière statique ou dynamique. Un décorateur fournit une interface améliorée à l'objet d'origine.

Dans la mise en œuvre de ce modèle, nous préférons la composition à un héritage - afin de pouvoir réduire les frais généraux de sous-classement encore et encore pour chaque élément de décoration. La récursivité impliquée dans cette conception peut être utilisée pour décorer notre objet autant de fois que nécessaire.

2. Exemple de modèle de décorateur

Supposons que nous ayons un objet sapin de Noël et que nous voulions le décorer. La décoration ne change pas l'objet lui-même; c'est juste qu'en plus du sapin de Noël, nous ajoutons des objets de décoration tels que guirlande, guirlandes, décorations d'arbre, lumières à bulles, etc.:

Pour ce scénario, nous suivrons les conventions de conception et de dénomination originales de Gang of Four. Tout d'abord, nous allons créer une interface ChristmasTree et son implémentation:

public interface ChristmasTree { String decorate(); }

L'implémentation de cette interface ressemblera à:

public class ChristmasTreeImpl implements ChristmasTree { @Override public String decorate() { return "Christmas tree"; } }

Nous allons maintenant créer une classe abstraite TreeDecorator pour cet arbre. Ce décorateur implémentera l' interface ChristmasTree et contiendra le même objet. La méthode implémentée depuis la même interface appellera simplement la méthode decorate () depuis notre interface:

public abstract class TreeDecorator implements ChristmasTree { private ChristmasTree tree; // standard constructors @Override public String decorate() { return tree.decorate(); } }

Nous allons maintenant créer un élément de décoration. Ces décorateurs étendront notre classe abstraite TreeDecorator et modifieront sa méthode decorate () en fonction de nos besoins:

public class BubbleLights extends TreeDecorator { public BubbleLights(ChristmasTree tree) { super(tree); } public String decorate() { return super.decorate() + decorateWithBubbleLights(); } private String decorateWithBubbleLights() { return " with Bubble Lights"; } }

Dans ce cas, ce qui suit est vrai:

@Test public void whenDecoratorsInjectedAtRuntime_thenConfigSuccess() { ChristmasTree tree1 = new Garland(new ChristmasTreeImpl()); assertEquals(tree1.decorate(), "Christmas tree with Garland"); ChristmasTree tree2 = new BubbleLights( new Garland(new Garland(new ChristmasTreeImpl()))); assertEquals(tree2.decorate(), "Christmas tree with Garland with Garland with Bubble Lights"); }

Notez que dans le premier objet tree1 , nous ne le décorons qu'avec un seul Garland , tandis que l'autre objet tree2 que nous décorons avec un BubbleLights et deux Garlands . Ce modèle nous donne cette flexibilité pour ajouter autant de décorateurs que nous le souhaitons au moment de l'exécution.

4. Conclusion

Dans cet article, nous avons examiné le modèle de conception du décorateur. C'est un bon choix dans les cas suivants:

  • Lorsque nous souhaitons ajouter, améliorer ou même supprimer le comportement ou l'état des objets
  • Lorsque nous voulons simplement modifier la fonctionnalité d'un seul objet de classe et laisser les autres inchangés

Le code source complet de cet exemple est disponible à l'adresse over sur GitHub.