Le motif de décorateur en Java

Le modèle de décorateur en Java

1. Vue d'ensemble

A Decorator pattern can be used to attach additional responsibilities to an object either statically or dynamically. Un décorateur fournit une interface améliorée avec l'objet d'origine.

Dans la mise en œuvre de ce modèle, nous préférons la composition à un héritage - afin de réduire les frais généraux liés aux sous-classes pour chaque élément de décoration. La récursion 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 d’arbre 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 de l’arbre de Noël, nous ajoutons des objets de décoration tels que guirlande, guirlandes, décorations d’arbre, bulles, etc.

image

For this scenario, we’ll follow the original Gang of Four design and naming conventions. Tout d'abord, nous allons créer une interfaceChristmasTree 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 abstraiteTreeDecorator pour cet arbre. Ce décorateur implémentera l'interfaceChristmasTree et contiendra le même objet. La méthode implémentée à partir de la même interface appellera simplement la méthodedecorate() 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 abstraiteTreeDecorator et modifieront sa méthodedecorate() selon 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 objettree1, nous ne le décorons qu'avec un seulGarland, tandis que l'autre objettree2 que nous décorons avec unBubbleLights et deuxGarlands. Ce modèle nous donne la possibilité d'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 de décorateur. C'est un bon choix dans les cas suivants:

  • Quand on veut ajouter, améliorer ou même supprimer le comportement ou l'état des objets

  • Quand on veut juste modifier la fonctionnalité d'un seul objet de la classe et laisser les autres inchangés

Le code source complet de cet exemple est disponibleover on GitHub.