Het decorateurpatroon in Java

1. Overzicht

Een decorateurpatroon kan worden gebruikt om zowel statisch als dynamisch extra verantwoordelijkheden aan een object te koppelen. Een decorateur biedt een verbeterde interface voor het originele object.

Bij de implementatie van dit patroon geven we de voorkeur aan compositie boven een overerving - zodat we de overhead van subclassificatie keer op keer voor elk decoratie-element kunnen verminderen. De recursie die bij dit ontwerp is betrokken, kan worden gebruikt om ons object zo vaak te versieren als we nodig hebben.

2. Voorbeeld van een decorateurpatroon

Stel dat we een kerstboomobject hebben en we willen het versieren. De versiering verandert het object zelf niet; het is gewoon dat we naast de kerstboom enkele decoratie-items toevoegen, zoals slinger, klatergoud, boomtopper, bellenlichten, enz .:

Voor dit scenario volgen we de oorspronkelijke ontwerp- en naamgevingsconventies van Gang of Four. Eerst maken we een Kerstboom interface en de implementatie ervan:

openbare interface ChristmasTree {String decorate (); }

De implementatie van deze interface ziet er als volgt uit:

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

We gaan nu een samenvatting maken TreeDecorator klasse voor deze boom. Deze decorateur zal het Kerstboom interface en houd hetzelfde object vast. De geïmplementeerde methode van dezelfde interface zal gewoon de versieren() methode van onze interface:

openbare abstracte klasse TreeDecorator implementeert ChristmasTree {private ChristmasTree tree; // standard constructors @Override public String decorate () {return tree.decorate (); }}

We gaan nu een decoratief element maken. Deze decorateurs zullen ons abstract uitbreiden TreeDecorator class en zal zijn versieren() methode volgens onze eis:

openbare klasse BubbleLights breidt TreeDecorator uit {openbare BubbleLights (ChristmasTree-boom) {super (boom); } public String decorate () {return super.decorate () + decorateWithBubbleLights (); } private String decorateWithBubbleLights () {return "with Bubble Lights"; }}

Voor dit geval geldt het volgende:

@Test openbare leegte whenDecoratorsInjectedAtRuntime_thenConfigSuccess () {ChristmasTree tree1 = nieuwe Garland (nieuwe ChristmasTreeImpl ()); assertEquals (tree1.decorate (), "Kerstboom met slinger"); ChristmasTree tree2 = nieuwe BubbleLights (nieuwe Garland (nieuwe Garland (nieuwe ChristmasTreeImpl ()))); assertEquals (tree2.decorate (), "Kerstboom met guirlande met guirlande met bellenlichten"); }

Merk op dat in de eerste boom1 object, we decoreren het met slechts één Guirlande, terwijl de andere boom2 object waarmee we decoreren BubbleLights en twee Slingers. Dit patroon geeft ons de flexibiliteit om tijdens runtime zoveel decorateurs toe te voegen als we willen.

4. Conclusie

In dit artikel hebben we het ontwerppatroon van de decorateur bekeken. Dit is een goede keuze in de volgende gevallen:

  • Wanneer we het gedrag of de toestand van objecten willen toevoegen, verbeteren of zelfs verwijderen
  • Wanneer we alleen de functionaliteit van een enkel object van klasse willen wijzigen en andere ongewijzigd willen laten

De volledige broncode voor dit voorbeeld is beschikbaar op GitHub.