[Design Pattern] Strukturelle Muster: Decorator

Thomas Darimont

Erfahrenes Mitglied
Hallo,

dieser Beitrag erklärt das Strukturelle Muster: Decorator
Java:
package de.tutorials.design.patterns.structural;

import org.jpatterns.gof.DecoratorPattern.ConcreteDecorator;
import org.jpatterns.gof.DecoratorPattern.Decorator;

public class DecoratorExample {
  
  public static void main(String[] args) {
    WrappableWithClothes human = new Jacket(new Pullover(new TShirt(new Undershirt(new Human(36.0)))));
    
    System.out.println("Human Body Temperature: " + human.getTemperature());
  }
  
  static class Human implements WrappableWithClothes{
    private double temperature;
    
    public Human(double temperature) {
      this.temperature = temperature;
    }

    public double getTemperature() {
      return temperature;
    }    
  }
  
  static interface WrappableWithClothes{
    double getTemperature();
  }

  
  @Decorator
  static abstract class Clothing implements WrappableWithClothes{
    protected WrappableWithClothes wrappable;
    
    public Clothing(WrappableWithClothes wrappable) {
      this.wrappable = wrappable;
    }

    public double getTemperature(){
      return wrappable.getTemperature() + getTemperatureContribution();
    }
    
    public double getTemperatureContribution(){
      return 0.0;
    }
  }
  
  @ConcreteDecorator
  static class Undershirt extends Clothing {
    public Undershirt(Human human) {
      super(human); //naked
    }
    @Override
    public double getTemperatureContribution() {
      return super.getTemperatureContribution() + 0.05;
    }
  }
  
  @ConcreteDecorator
  static class TShirt extends Clothing {
    public TShirt(Clothing beneath) {
      super(beneath);
    }
    
    @Override
    public double getTemperatureContribution() {
      return super.getTemperatureContribution() + 0.1;
    }
  }
  
  @ConcreteDecorator
  static class Pullover extends Clothing {
    public Pullover(Clothing beneath) {
      super(beneath);
    }
    
    @Override
    public double getTemperatureContribution() {
      return super.getTemperatureContribution() + 0.2;
    }
  }
  
  @ConcreteDecorator
  static class Jacket extends Clothing {

    public Jacket(Clothing beneath) {
      super(beneath);
    }
    
    @Override
    public double getTemperatureContribution() {
      return super.getTemperatureContribution() + 0.5;
    }
  }
}

Ausgabe:
Code:
Human Body Temperature: 36.85

Gruß Tom
 

BE23532

Grünschnabel
Hallo,

ich bin zufällig auf dieses Forum gestoßen und hoffe, dass man mir helfen kann.

Ich habe die Beschreibungen der Design Patterns und die Code Beispiele mehrmals durchgelesen,
allerdings schaffe ich es nicht bei einem vorgegeben Code rauszufinden um welchen Design Pattern
es sich handelt. Ich habe die Vermutung das es der Decorator ist aber kann wie gesagt nie sicher sein.
Gibt es im Forum eine spezielle "Frage Ecke" oder kann ich meinen Code hier posten?

Vielen Dank schonmal.
 

Thomas Darimont

Erfahrenes Mitglied
Hallo,

poste das Beispiel doch einfach hier - manchmal ist es schwer die Design Patterns auseinander zu halten z.Bsp. Proxy und Decorator.

Gruß Tom
 

BE23532

Grünschnabel
Hier ist auf den Seiten 1-3 der Code.
Wie man auf Seite 3 sieht geht es darum rauszufinden welches Muster dieser Code verwendet.
Ich schwanke zwischen Strategie und Dekorierer. Beobachter kann ich sicher ausschließen.
 

Anhänge

  • ProbeklausurSWE.pdf
    213,6 KB · Aufrufe: 35

Akeshihiro

Erfahrenes Mitglied
Also ich kann da keines der drei Pattern wiederfinden ...

Beobachter ist es auf keinen Fall, da hast du recht.

Ein Decorator ist es aber ebenfalls nicht, da das komplette Gerüst für ein Decorator-Pattern fehlt. Sonnenblume implementiert lediglich das Interface Bild, mehr aber auch nicht. Das wäre also eine konkrete Implementierung. Daneben bräuchtest du eigentlich noch eine abstrakte Implementierung einer Decorator-Klasse, die ebenfalls das Inteface implementiert (damit der Decorator als Bild auftreten kann) und davon abgeleitet kämen dann die konkreten Decorator. Davon fehlt hier jedoch jegliche Spur.

Bei Strategy wird es schon etwas schwerer, denn eine gewisse Gemeinsamkeit ist gegeben. Aber beim Strategy-Pattern ist der Knackpunkt der, dass man von Außerhalb des Kontextes (Sonnenblume) die Strategie für den Kontext ändern kann. Das ist der Sinn von Strategy, man kann zur Laufzeit die Strategie und somit das Verhalten ändern. Das ist hier ebenfalls nicht der Fall. Die Methoden delegieren zwar die Aufrufe an ein Objekt vom Typ PImage, das ist dem Strategy-Pattern also sehr ähnlich, aber der Grundgedanke fehlt. Das ist in meinen Augen bestenfalls eine gekapselte Delegation.
 
Zuletzt bearbeitet:

Thomas Darimont

Erfahrenes Mitglied
Hallo,

ich sehe im Programm unter 1. auch nur die Aspekte:
- Kapselung
- Schnittstellen
- Über Komposition (PImage in Sonnenblume) ließe sich Diskutieren:

Laut wikipedia: http://de.wikipedia.org/wiki/Komposition_(UML)#Komposition
"Die Komposition (composite aggregation oder composition) als Sonderfall der Aggregation beschreibt ebenfalls die Beziehung zwischen einem Ganzen und seinen Teilen. Der Unterschied zur Aggregation ist, dass die Existenz eines Objekts, das Teil eines Ganzen ist, von der Existenz des Ganzen abhängig ist."

Wenn also die Sonnenblume von der existenz eines PImage abhängig ist - ohne PImage gibt es keine Bild-Daten - dann liegt eine Komposition vor.

Die genannten Patterns sind IMHO im Beispiel nicht enthalten.



Gruß Tom
 

takidoso

Erfahrenes Mitglied
Hi Tom
Im Ganzen stimme ich zu.
jedoch ...
...
Wenn also die Sonnenblume von der existenz eines PImage abhängig ist - ohne PImage gibt es keine Bild-Daten - dann liegt eine Komposition vor.
...
sehe ich irgendwie genau anders herum.
Wenn Sonnenblume nicht existiert, existiert auch PImage nicht.
Würde also PImage noch existieren, wenn das PImage aufnehmende Objekt Sonnenblume nicht mehr existiert, weil irgendwo die Bilddaten noch woanders, .B. in einem Cache, Verwendung finden, dann wäre es keine Komposition.
Also würde ich PImage als Teil und die Sonenblume als das Ganze ansehen und würde bei einer Komposition mit Löschen der Sonnenblume auch der Teil der Bildaten (PImage) gelöscht werden.
 

slowfly

Erfahrenes Mitglied
Das Design einer Applikation gibt vor, wie die Applikation implementiert werden soll. Wenn man eine Komposition designed und beim Löschen des Ganzen seine Teile nicht löscht, dann wurde es eben falsch implementiert ;)

Aber ich glaube, es kommt nicht so oft vor, dass man eine Komposition designed und peinlichst darauf achtet, dass es auch so implementiert wird,...

Gruss
slowy
 

takidoso

Erfahrenes Mitglied
also ich glaube wir reden da nun etwas auseinander.
Eine typische Situation einre Komposition könnte zum beispiel ein Stuhl sein in Bezug seiner Bestandteile (Lehne, Beine etc.) Kompositionen kommen aus meiner Sicht häfig vor one dass man sich nähee Gedanken macht.
Geht der Stuhl in die Schrottpresse oder ins Feuer sind auch seine Beinde und seine Lehne dran :)
Was zum Beispiel keine Komposition ist, wäre eine Auto und eine Garage. Es ist eine lockere Assoziation, denn man muss ja nicht immer dasselbe Auto in die Garage stellen, und kommt dass Auto in die Schrottpresse steht die Garage imme noch da :)
 
Zuletzt bearbeitet:

slowfly

Erfahrenes Mitglied
Ein Stuhlbein kann man austauschen ;-) -> unabhängig davon, dass es schwierig ist ein Beispiel hinzubekommen, das ohne irgend eine Ausnahme auskommt:

Mir geht es mit meinen Aussagen darum, dass eine Komposition in Java "schwierig" (oder eher mühsam) zu implementieren ist. Nehmen wir mal das Beispiel Haus -> Raum.
Code:
class Haus{
  private List<Raum> räume;

  get/setRäume
}

Das ist schon mal falsch, das würde bedeutet, dass ich irgendwo "new Raum" machen muss -> schon existiert ein Raum ohne Haus, was dann keine Komposition ist.

Dann könnte man sowas machen:
Code:
class Haus{
  private List<Raum> räume;

  void addRaum(String raumname, Stockwerk stockwerk, whatever...){
  }

  private class Raum{
    public Raum(Haus parent, ...){
    }
  }
}
Nur hat man dann eine private class, mit welchem nur das Haus arbeiten kann. Raum.neuStreichen() geht jetzt nicht, ich müsste über Haus.streichen(Raum, Farbe) gehen, was auch nicht geht, da es ja eine private class ist.

Und wenn man Raum public macht und über eine getter-Methode an die Räume kommt, passiert sowas:
Code:
  Haus haus = new Haus();
  haus.addRaum(bla);
  haus.addRaum(noch einer);
  List<Raum> räume = haus.getRäume();
  haus = null;
Was passiert? Haus erstellen, Räume hinzufügen, Räume holen, Referenz von haus auf null setzen. Und nun kommt der GarbageCollector und räumt das Haus auf -> es existiert nicht mehr physisch. Jedoch die Räume existieren -> also keine Komposition.

Nunja, vielleicht sehe ich das etwas zu streng,... aber egal, my two pence ;)

Gruss,
slowy
 

Neue Beiträge