Il motivo Decorator in Java

1. Panoramica

Un motivo Decorator può essere utilizzato per attribuire responsabilità aggiuntive a un oggetto in modo statico o dinamico. Un decoratore fornisce un'interfaccia avanzata all'oggetto originale.

Nell'implementazione di questo modello, preferiamo la composizione a un'eredità, in modo da poter ridurre il sovraccarico della sottoclasse ancora e ancora per ogni elemento di decorazione. La ricorsione coinvolta in questo disegno può essere usata per decorare il nostro oggetto tutte le volte che ne abbiamo bisogno.

2. Esempio di motivo per decoratore

Supponiamo di avere un oggetto per l'albero di Natale e di volerlo decorare. La decorazione non cambia l'oggetto stesso; è solo che oltre all'albero di Natale, stiamo aggiungendo alcuni elementi decorativi come ghirlande, orpelli, copri-albero, luci a bolle, ecc .:

Per questo scenario, seguiremo le convenzioni di design e denominazione originali di Gang of Four. Innanzitutto, creeremo un'interfaccia ChristmasTree e la sua implementazione:

public interface ChristmasTree { String decorate(); }

L'implementazione di questa interfaccia sarà simile a:

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

Creeremo ora una classe TreeDecorator astratta per questo albero. Questo decoratore implementerà l' interfaccia ChristmasTree e manterrà lo stesso oggetto. Il metodo implementato dalla stessa interfaccia chiamerà semplicemente il metodo decorate () dalla nostra interfaccia:

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

Creeremo ora qualche elemento decorativo. Questi decoratori estenderanno la nostra classe TreeDecorator astratta e modificheranno il suo metodo decorate () in base alle nostre esigenze:

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"; } }

In questo caso, è vero quanto segue:

@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"); }

Nota che nel primo oggetto albero1 , lo stiamo decorando solo con una sola ghirlanda , mentre l'altro oggetto albero2 lo stiamo decorando con una BubbleLight e due ghirlande . Questo modello ci offre questa flessibilità per aggiungere tutti i decoratori che vogliamo in fase di esecuzione.

4. Conclusione

In questo articolo, abbiamo esaminato il modello di progettazione del decoratore. Questa è una buona scelta nei seguenti casi:

  • Quando desideriamo aggiungere, migliorare o persino rimuovere il comportamento o lo stato degli oggetti
  • Quando vogliamo solo modificare la funzionalità di un singolo oggetto di classe e lasciare gli altri inalterati

Il codice sorgente completo per questo esempio è disponibile su GitHub.