Decorator (Design Pattern): Unterschied zwischen den Versionen
(Die Seite wurde neu angelegt: „In unserer Designs ist es oft nützlich, das Verhalten eines Objektes zur Laufzeit zu erweitern, ohne vorhandenen Code ändern zu müssen. Wir können die Komp…“) |
|||
Zeile 137: | Zeile 137: | ||
* die Anwesenheit der Eigenschaft "pet", die sich auf die Komponente bezieht, die vom Decorator umhüllt wird. | * die Anwesenheit der Eigenschaft "pet", die sich auf die Komponente bezieht, die vom Decorator umhüllt wird. | ||
− | * das Hinzufügen eines neuen Verhaltens in der Methode laut() nach dem Aufruf der Methode laut() der Komponente: '''return pet.laut() + "schnurren", ''' (in PetSchnurrend) und '''return pet.laut() + "fauchen"; ''' (in PetFauchend) | + | * das Hinzufügen eines neuen Verhaltens in der Methode laut() nach dem Aufruf der Methode laut() der Komponente: '''return pet.laut() + ", schnurren", ''' (in PetSchnurrend) und '''return pet.laut() + ", fauchen"; ''' (in PetFauchend) |
Schließlich ist hier die Startklasse der Anwendung "MeineTierschau" | Schließlich ist hier die Startklasse der Anwendung "MeineTierschau" |
Version vom 4. Oktober 2012, 13:01 Uhr
In unserer Designs ist es oft nützlich, das Verhalten eines Objektes zur Laufzeit zu erweitern, ohne vorhandenen Code ändern zu müssen. Wir können die Komposition und die Delegation benutzen, um neue Verhaltensweisen zur Laufzeit hinzufügen.
Das Decorator Design Pattern fügt einem Objekt dynamisch Verantwortung hinzu. Zwecks Erweiterung der Funktionalität eines Objekts, bietet das Decorator Design Pattern eine flexible Alternative zur Vererbung.
Das Decorator Design Pattern impliziert die Schaffung einer Reihe von Decorator-Klassen, welche die Komponenten umhüllen.
- Decorator-Klassen sind vom gleichen Typ wie die Komponenten, die sie umhüllen (der Typ wird entweder durch Vererbung oder durch die Implementierung einer Schnittstelle festgelegt).
- Die "Decorators" verändern das Verhalten ihrer Komponenten durch Hinzufügen neuer Features vor, nach oder anstelle von Aufrufen von Methoden der Komponente.
- Wir können eine Komponente mit einer beliebige Anzahl von "Decorators" umhüllen.
- Die "Decorators" sind transparent für den Kunden, sofern der Kunde auf dem abstrakten Obertyp der Komponente aufbaut, und nicht auf konkreten Untertypen.
Nehmen wir zum Beispiel den abstrakten Obertyp "Pet"
<code=java>package tierschau;
public abstract class Pet {
private int age; private String species;
public Pet(final int age) { this.age = age; }
public int age() { return age; }
public String species() { return species; }
public void setSpecies(final String species) { this.species = species; }
public abstract String laut();
@Override public String toString() { return "Ich bin ein(e) " + species + "; ich bin " + age + " Jahre alt; ich kann '" + laut() + "' !"; }
} </code=java>
und den konkrete Untertyp "Katze", der von "Pet" abgeleitet ist:
<code=java>package tierschau;
public class Katze extends Pet {
public Katze(final int age) { super(age); super.setSpecies(getClass().getSimpleName()); }
@Override public String laut() { return "miauen"; }
} </code=java>
Wir haben den Namen der konkreten Klasse in der Eigenschaft "species" der abstrakten Klasse "Pet" gespeichert (um zu vermeiden, dass wir uns zu einem späteren Zeitpunkt auf die konkrete Klasse "Katze" beziehen müssen).
Um das Verhalten eines "Pet" zu erweitern, führen wir den abstrakten Decorator "PetBehavior" hinzu. Erinnern wir uns daran, dass der Decorator den gleichen Typ hat wie die Komponente, die er umhüllt. Das ist der Grund, weshalb wir ihn von "Pet" ableiten:
<code=java>package tierschau;
public abstract class PetBehavior extends Pet {
public PetBehavior(final int age) { super(age); }
} </code=java>
Wir verwirklichen den abstrakten "Decorator" durch die zwei konkreten Implementierungen "PetSchnurrend" und "PetFauchend":
<code=java>package tierschau;
public class PetSchnurrend extends PetBehavior {
private final Pet pet;
public PetSchnurrend(final Pet pet) { super(pet.age()); this.pet = pet; setSpecies(pet.species()); }
@Override public String laut() { return pet.laut() + ", schnurren"; }
} </code=java>
<code=java>package tierschau;
public class PetFauchend extends PetBehavior {
private final Pet pet;
public PetFauchend(final Pet pet) { super(pet.age()); this.pet = pet; setSpecies(pet.species()); }
@Override public String laut() { return pet.laut() + ", fauchen"; }
} </code=java>
Beachten wir in diesen konkreten "Decorators":
- die Anwesenheit der Eigenschaft "pet", die sich auf die Komponente bezieht, die vom Decorator umhüllt wird.
- das Hinzufügen eines neuen Verhaltens in der Methode laut() nach dem Aufruf der Methode laut() der Komponente: return pet.laut() + ", schnurren", (in PetSchnurrend) und return pet.laut() + ", fauchen"; (in PetFauchend)
Schließlich ist hier die Startklasse der Anwendung "MeineTierschau"
<code=java>package tierschau;
public class MeineTierschau {
public static void main(final String[] args) { Pet animal = new Katze(4); System.out.println(animal); animal = new PetSchnurrend(animal); //den Pet mit PetSchnurrend umhüllen System.out.println(animal); animal = new PetFauchend(animal); //den Pet mit PetFauchend umhüllen System.out.println(animal); }
} </code=java>
Das Programm gibt die folgenden Zeilen auf der Konsole aus:
- Ich bin ein(e) Katze; ich bin 4 Jahre alt; ich kann 'miauen' !
- Ich bin ein(e) Katze; ich bin 4 Jahre alt; ich kann 'miauen, schnurren' !
- Ich bin ein(e) Katze; ich bin 4 Jahre alt; ich kann 'miauen, schnurren, fauchen' !
Am Ende sehen wir, dass die Katze sowohl von PetSchnurrend als auch von PetFauchend umhüllt wurde. Auf diese Weise könnte sie mit einer beliebige Anzahl von Decorators umhüllt werden.