Das Dekorationsmuster in Java

1. Übersicht

Ein Decorator-Muster kann verwendet werden, um einem Objekt entweder statisch oder dynamisch zusätzliche Verantwortlichkeiten zuzuweisen. Ein Decorator bietet eine erweiterte Schnittstelle zum Originalobjekt.

Bei der Implementierung dieses Musters bevorzugen wir die Komposition gegenüber einer Vererbung, damit wir den Aufwand für die Unterklasse für jedes Dekorationselement immer wieder reduzieren können. Die mit diesem Entwurf verbundene Rekursion kann verwendet werden, um unser Objekt so oft zu dekorieren, wie wir es benötigen.

2. Beispiel für ein Dekorationsmuster

Angenommen, wir haben ein Weihnachtsbaumobjekt und möchten es dekorieren. Die Dekoration verändert das Objekt selbst nicht; Es ist nur so, dass wir zusätzlich zum Weihnachtsbaum einige Dekorationsgegenstände wie Girlanden, Lametta, Baumkronen, Blasenlichter usw. hinzufügen.

In diesem Szenario folgen wir den ursprünglichen Design- und Namenskonventionen der Gang of Four. Zuerst erstellen wir eine ChristmasTree- Oberfläche und deren Implementierung:

public interface ChristmasTree { String decorate(); }

Die Implementierung dieser Schnittstelle sieht folgendermaßen aus:

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

Wir erstellen jetzt eine abstrakte TreeDecorator- Klasse für diesen Baum. Dieser Dekorateur implementiert die ChristmasTree- Oberfläche und hält dasselbe Objekt. Die implementierte Methode von derselben Schnittstelle ruft einfach die Methode decorate () von unserer Schnittstelle aus auf:

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

Wir werden jetzt ein Dekorationselement erstellen. Diese Dekoratoren erweitern unsere abstrakte TreeDecorator- Klasse und ändern ihre decorate () -Methode gemäß unseren Anforderungen:

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

Für diesen Fall gilt Folgendes:

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

Beachten Sie, dass wir im ersten tree1- Objekt nur mit einer Girlande dekorieren , während wir im anderen tree2- Objekt mit einer BubbleLights und zwei Garlands dekorieren . Dieses Muster gibt uns die Flexibilität, zur Laufzeit so viele Dekorateure hinzuzufügen, wie wir möchten.

4. Fazit

In diesem Artikel haben wir uns das Dekorationsmuster angesehen. Dies ist in folgenden Fällen eine gute Wahl:

  • Wenn wir das Verhalten oder den Status von Objekten hinzufügen, verbessern oder sogar entfernen möchten
  • Wenn wir nur die Funktionalität eines einzelnen Klassenobjekts ändern und andere unverändert lassen möchten

Der vollständige Quellcode für dieses Beispiel ist auf GitHub verfügbar.