English English

Java Pattern Decorater - Erweitern Sie Ihre Objektfunktionalität dynamisch auf strukturierte Weise

Dieses Pattern (Entwurfsmuster) wird verwendet, um die Funktionalität von Objekten zu erweitern, ohne die Verwendung von Vererbung oder Änderung des ursprünglichen Programmiercodes. Dies ist ein Teil der Serie "Design-Pattern in Java".

Was ist ein Decorator?

Ein Decorater (Dekorateur) ist ein Entwurfsmuster (das in der Programmierung im Allgemeinen verwendet wird), um die Funktionalität eines Objekts durch die Erstellung eines Wrapper-Objekts zu erweitern.
Dieses Wrapper-Objekt, das als Dekorator bezeichnet wird, wird verwendet, um das ursprüngliche Objekt, das erweitert werden soll, zu umhüllen.

Das Dekorationsobjekt hat die gleichen Funktionen wie das zu umhüllende Originalobjekt. Sie können es aber auch mit spezifischen Funktionen erweitern, die von diesem Dekorator verwendet werden.
Die Funktionalität des Dekorator-Objekts wird zur Laufzeit Ihrer Anwendung hinzugefügt.

Ein UML-Diagramm einer Anwendung, die das Entwurfsmuster "Decorator" verwendet.

Das Interface (Schnittstelle) "Burger": Dieses Interface wird auch als "Komponente" bezeichnet und definiert die Methoden, die von der Klasse implementiert werden, die später hinzugefügt werden.
Die Klasse "ChickenBurger": Diese Klasse ist die Implementierung der "Komponente". Es kann mehrere Klassen geben, die ebenfalls die "Komponente" implementieren.
Die abstrakte Klasse "BurgerDecorator": Dies ist der Decorator, der unser ursprüngliches Burger-Objekt schmückt und der das "Component"-Objekt enthält. Auf die in dieser Klasse definierten Instanzobjekte wird von den Unterklassen zugegriffen.
Die Klassen "Exotic", "Mozarella" and "Vegetables": Das sind die konkreten Dekorateure. Sie setzen die Dekorationsfunktionalität um und können mit ihrer jeweiligen Funktionalität erweitert werden.

 

Eine Beispielanwendung

Dies ist eine Beispielanwendung namens "TastyBurgers", die die Realisierung des obigen UML-Diagramms darstellt.
Mit Hilfe dieses Beispiels werden Sie ein praktischeres Verständnis dieses Design-Patterns (Entwurfsmuster) erhalten.

 

a. Schnittstelle (Interface) der Komponente

public interface Burger {
	String getName();
	Integer getToppingsAmount();
}

Hier werden alle Methoden definiert, die zumindest für einen Burger zur Verfügung stehen.

 

b. Implementierung der Komponente

public class ChickenBurger implements Burger {	
	
	public ChickenBurger() {
	}
	
	@Override
	public String getName() {
		return "Standard Chicken Burger";
	}

	@Override
	public Integer getToppingsAmount() {
		return 0;
	}

}

 

c. Decorator-Klasse

public abstract class BurgerDecorator implements Burger{

	protected Burger burger;
	
	public BurgerDecorator(Burger b) {
		this.burger=b;
	}
	
	@Override
	public String getName() {
		return burger.getName();
	}

	@Override
	public Integer getToppingsAmount() {
		return burger.getToppingsAmount();
	}
	
}

Diese abstrakte Klasse implementiert die definierte Schnittstelle (Interface) eines Burgers.

 

d. Concrete Decorators

public class Exotic extends BurgerDecorator{

	public Exotic(Burger b) {
		super(b);
	}
	
	@Override
	public String getName() {
		return "Exotic Flavour Edition";
	}

	@Override
	public Integer getToppingsAmount() {
		return 5;
	}
	
	//Extended functionality - Only available in an Exotic Burger
	public Integer getSpicinessLevel() {
		return 10;
	}

}
public class Mozarella extends BurgerDecorator{
	
	public Mozarella(Burger b) {
		super(b);
	}
	
	@Override
	public String getName() {
		return "Mozarella Cheese";
	}

	@Override
	public Integer getToppingsAmount() {
		return 2;
	}

}
public class Vegetables extends BurgerDecorator {

	public Vegetables(Burger b) {
		super(b);
	}

	@Override
	public String getName() {
		return "Healthy Vegetables Edition";
	}

	@Override
	public Integer getToppingsAmount() {
		return 4;
	}
}

Die Funktionserweiterungen werden hier hinzugefügt.

Die erstellten Dekorateure können in diesem Format aufgerufen werden:

public class TastyBurgers {

	public static void main(String[] args) {
		Burger burgerA = new Mozarella(new ChickenBurger());
		Burger burgerB = new Exotic(new ChickenBurger());
		Burger burgerC = new Vegetables(new ChickenBurger());
		System.out.println("Burger A Name: " + burgerA.getName() + " - Toppings No.: " + burgerA.getToppingsAmount());
		System.out.println("Burger B Name: " + burgerB.getName() + " - Toppings No.: " + burgerB.getToppingsAmount());
		System.out.println("Burger C Name: " + burgerC.getName() + " - Toppings No.: " + burgerC.getToppingsAmount());
		//The function which was extended (class: Exotic) can be accessed only if you define an object directly with the class name "Exotic":
		Exotic burgerBExtended = new Exotic(new ChickenBurger());
		System.out.println("Burger B Extended - Name: " + burgerBExtended.getName() + " - Toppings No.: " + burgerBExtended.getToppingsAmount() + " - Spiciness Level: " + burgerBExtended.getSpicinessLevel());

	}
}

Ausgabe:

Burger A Name: Mozarella Cheese - Toppings No.: 2
Burger B Name: Exotic Flavour Edition - Toppings No.: 5
Burger C Name: Healthy Vegetables Edition - Toppings No.: 4
Burger B Extended - Name: Exotic Flavour Edition - Toppings No.: 5 - Spiciness Level: 10

Wenn Sie eine erweiterte Funktionalität in einem konkreten Dekorator verwenden wollen, dann müssen Sie das Objekt direkt ohne die Interface-Klasse deklarieren.

Dies war ein Beispiel für einen Dekorator. Wenn Sie in Java programmieren, dann finden Sie regelmäßig Java-Klassen, die das "Decorator Pattern" verwenden. Zum Beispiel BufferedInputStream oder BufferedOutputStream.

 

Diese Applikation als Projekt auf Github:

https://github.com/a-dridi/decorator-tastyburgers

 

Cookies erleichtern die Bereitstellung unserer Dienste. Mit der Nutzung unserer Dienste erklären Sie sich damit einverstanden, dass wir Cookies verwenden.
Ok