Laden...

[Artikel] Entwurfsmuster: Decorator

Erstellt von pro vor 16 Jahren Letzter Beitrag vor 16 Jahren 26.531 Views
P
pro Themenstarter:in
216 Beiträge seit 2006
vor 16 Jahren
[Artikel] Entwurfsmuster: Decorator

Einführung:

Wiedermal darf ich ein Entwurfsmuster kennenlernen. Diesmal ist es das Decorator Pattern. Um es vorweg zu nehmen, bei der folgenden kleinen “Vorstellung” des Decoratorpattern, wird das Entwurfsmuster nicht in Kombination mit dem Factory Pattern aufgezeigt. Es geht einzig um das Decorator Pattern.

Das Decoratorpattern kann man in einem UML Klassendiagramm so aufzeichnen :

Defintion:

Das Decoratormuster fügt einem Objekt dynamisch zusätzliche Verantwortlichkeiten hinzu. Dekorierer bieten eine flexible Alternative zur Ableitung von Unterklassen zum Zweck der Erweiterung der Funktionalität.

Zusammenfassung:

Die Definition sagt nichts anderes aus, als dass die oben aufgezeichneten Komponenten dynamisch erweitert (oder eben dekoriert) werden können. Dynamisch bedeutet hier, dass man die Funktionalitäten zur Laufzeit beliebig hinzufügen kann.

Beispiel - Ein Menü Dekorierer 🙂

Das Beispiel hat nichts mit dem Programmieralltag zu tun. Jedoch eigenen sich Menü’s extrem zum dekorieren.

Es gibt in einem Restaurant zwei Menues (Menü 1 und Menu 2). Ein Kunde kann aber diese Menues beliebig erweitern wie er will. D.h. er kann zu einem Menu noch ein Hamburger, Pommes Frites oder Nuggets bestellen. Dies bedeutet, dass er die beiden Menues um die Zutaten beliebig erweitern (oder eben “dekorieren” ) kann.

Das Klassendiagramm dieser Menues sieht dann auf das Decoratormuster umgesetzt so aus :

Implementierung (auf Restaurant - Beispiel bezogen)

Abstrakte Komponenten Klasse (Menu) :


/// <summary>
/// Abstrakte Komponente (Menu)
/// Alle Komponenten müssen von dieser "Hauptkomponente"
///erben, damit sie dekoriert werden können.
/// </summary>
public abstract class Menu
{
/// <summary>
/// Feld, welches durch das ganze Decoratormuster
///hindurchgezogen wird.
/// In diesem Fall Description. Wird in jeder
/// Komponente bzw. Dekorierer
/// anders sein
/// </summary>
protected string description = "menu";

/// <summary>
/// Property, welche die Unterklassen benötigen,
/// um auf die Oberklasse / Superklasse /
///Baseklasse zugreifen zu können
/// </summary>
public abstract string Description { get; }

/// <summary>
/// Zu überschreibende Methode Preis, welche
/// durch die Komponenten statisch, bzw. durch die Dekorierer
/// dynamisch gesetzt werden
/// </summary>
/// <returns>Preis</returns>
public abstract double Preis();
}


Eine konkrete Komponente (Menu_1):


/// <summary>
/// Komponente 1
/// </summary>
public class Menu_1 : Menu
{
/// <summary>
/// Konstruktor der Komponente
/// </summary>
public Menu_1()
{
this.description = "Menu_1";
}

/// <summary>
/// Überschriebene Methode, der
///Abstrakten- bzw. Hauptkomponente
/// (statischer Preis der Komponente, ohni "Dekorierungen";)
/// </summary>
/// <returns>Preis</returns>
public override double Preis()
{
return 11.00;
}

/// <summary>
/// Überschriebens Description Property
/// </summary>
public override string Description
{
get { return this.description; }
}


Abstrakter Dekorierer (Erbt von Menu, da das dekorierte Objekt schlussendlich auch wieder eine Komponente ist)


/// <summary>
/// Hauptdekorierer
/// (Alle konkreten Dekorierer werden
///von diesem Dekorierer ableiten)
/// </summary>
public abstract class MenuDecorator : Menu
{
/// <summary>
/// Property oder Methode, welche Dekoriert werden soll
/// </summary>
public override string Description {
get { return this.description; }
}

Konkreter Dekorierer (in diesem Fall die Hamburger, welche zum Menu gehören)


/// <summary>
/// Dekorierer, welcher Hamburger zur Komponente hinzufügt
/// </summary>
public class HamburgerDecorator : MenuDecorator
{
/// <summary>
/// Objekt, welches dekoriert werden soll
/// </summary>
private Menu menu;

/// <summary>
/// Konstrukter des Dekorierers
/// </summary>
public HamburgerDecorator(Menu menu)
{
this.menu = menu;
}

/// <summary>
/// Beschreibung, welche durch den Dekorierer
/// dekoriert wird
/// (zur Menu Description kommt noch der dekorierte Text)
/// </summary>
public override string Description
{
get { return menu.Description + " + Hamburger"; }
}

/// <summary>
/// Dekorierter Preis
/// (da das Objekt um "Hamburger" erweitert wurde,
/// muss natürlich auch der Preis erhöht werden)
/// </summary>
/// <returns>Preis</returns>
public override double Preis()
{
return 2.50 + menu.Preis();
}
}

Verwendung der Dekorierer


/// <summary>
/// Main - Methode
/// </summary>
///
static void Main(string[] args)
{
//Ich möchte ein Menu_1 ohne weitere Zutaten ( 11.00 )
Menu menu = new Menu_1();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Ich möchte ein Menu_1 ohne weitere Zutaten"+
";( 11.00 )...";);
Console.WriteLine("Beschreibung : "
+ menu.Description + " / Preis : " + menu.Preis());
Console.WriteLine();

Console.ForegroundColor = ConsoleColor.Yellow;

//Ich möchte nun ein Menu_1 mit Hamburger
//(Achtung : menu ist bereits ein Menu_1 Objekt!
//Darum keine Menu_1 Instanzierung notwendig!)

//-- Hamburger hinzufügen ( + 2.50 )
menu = new HamburgerDecorator(menu);

Console.WriteLine("Ich möchte zu meinem" +
"bestellten Menu_1 (11.00) ein zusätzlicher" +
" Hamburger (2.50)..";);
Console.WriteLine("Beschreibung : "
+ menu.Description + " / Preis : " + menu.Preis());
Console.WriteLine();

Console.ForegroundColor = ConsoleColor.Cyan;

//Ich möchte nun ein Menu_1 mit
//zusätzlichem Hamburger und Chicken Nuggets
//(Achtung : menu ist bereits ein Menu_1 mit Hamburger!)

//--Hamburger hinzufügen ( + 2.50 )
menu = new HamburgerDecorator(menu);

//--Nuggets hinzufügen ( + 1.50 )
menu = new NuggetsDecorator(menu);

Console.WriteLine("Ich möchte nun zu meinem" +
" Menu_1 einen zusätzlichen Hamburger (2.50) und" +
"Chicken Nuggets (1.50)...";);
Console.WriteLine("Beschreibung : "
+ menu.Description + " / Preis : " + menu.Preis());
Console.WriteLine();

//Ich möchte nun ein Menu_2 mit Pommes und Nuggets
//menu wird durch die Neuinstanzierung überschrieben!!

//--Menu_2 erstellen (9.00)
menu = new Menu_2();

//--Pommes hinzufügen ( + 3.00)
menu = new PommesDecorator(menu);

//--Nuggets hinzufügen ( + 1.50)
menu = new NuggetsDecorator(menu);

Console.ForegroundColor = ConsoleColor.Yellow;

Console.WriteLine("Ich möchte nun ein neues " +
"Menu_2 (9.00) mit Pommes (3.00) und Nuggets (1.50)...";);
Console.WriteLine("Beschreibung : "
+ menu.Description + " / Preis : " + menu.Preis());

Console.WriteLine();

Console.WriteLine("Press <enter> to exit...";);</enter>

Console.ReadLine();

}

Das Schlussresultat der Beispielverwendung der Decorator sieht dann so aus:

Das Projekt als Download ist angehängt (=> VS05 Solution).

Weiterführende Links:

> http://en.wikipedia.org/wiki/Decorator_pattern
> http://exciton.cs.rice.edu/JavaResources/DesignPatterns/DecoratorPattern.htm
> http://www.onjava.com/pub/a/onjava/2003/02/05/decorator.html
> http://www.informit.com/articles/article.aspx?p=31350&seqNum=1
> http://www.codeproject.com/info/search.aspx?artkw=decorator&sbo=kw

Schlagwörter: Decorator, Pattern, Entwurfsmuster