Programming Design Patterns

Jaiel

Jaiel

Dauergast
235
Hallo,

befasse mich zu Lern und Lehrzwecken mit Programming Design Pattern, speziell alle aus dem GoF Buch. Ich werde ganz kurz die einzelnen Pattern hier vorstellen und auch jeweils ein Beispiel mit Code/s präsentieren.

Design Pattern dienen dazu das Leben des Programmierers einfacher zu gestalten, indem man für immer wieder auftretende Probleme in der Programmierung und Softwareentwicklung durch "bewährte" Entwurfsmuster zu Leibe rücken kann.

Programming Design Patterns

-> Creational Patterns
-> Structural Patterns
-> Behaviourial Patterns


Creational Patterns

- Abstract Factory
- Builder
- Factory Method
- Prototype
- Singleton


Structural Patterns

- Adapter
- Bridge
- Composite
- Decorator
- Facade
- Flyweight
- Proxy


Behavioural Patterns

- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: burgerohnealles, kosmus und vetzki
Creational Patterns

Abstract Factory Pattern:
Definition:
Dies ist eine Class Creational Pattern und wird benutzt um Klassenobjekte zu instanzieren. Es stellt dem Aufrufer einzelne Objekte oder Gruppen von Objekten zur Laufzeit zur Verfügung.


Beispiel:
Nehmen wir an ein Webstore versendet 2 Produkte: Ein normales Produkt, dass eine ganz normale Verpackung und normalen Versand erfordert. Das Andere ein zerbrechliches Produkt das besondere Verpackung benötigt und per Kurier verschickt werden soll. Dafür können wir 2 Factory Klassen benutzen und 2 Product Klassen. 1 Factory kümmert sich um die Verpackungsart des Produktes und eine um die Versandtart des Produktes.

AbstractFactory.png



Client:
Diese Klasse benutzt fabriken um eine "Familie" an verwandten Objekten zu erstellen. Der Client hält zwei private Felder an "Abstratct Product"'s. Die darunterliegenden Objekte stehen in Beziehung zueinander aber der Typ kann erstmal unbekannt bleiben.Wenn ein Client instanziert wird, wird als Parameter eine "ConcreteFactory" im Konstruktor übergeben und die privaten Felder werden initialisiert. In diesem Fall ist Client dann das "Produkt" welches alle nötigen Angaben hat. Die einzelnen konkreten Produkte stellen dar wie das Produkt verpackt und wie es versendet werden soll.

AbstractFactory:
Abstrakte Basisklasse für eine konkrete Fabrik Klasse. Eine Methode pro Produkt ist darin deklariert.

ConcreteFactory (A/B):
Erbt von "AbstractFactory". Die Methoden dieser Klassen überschreiben die deklarierten in der Basisklasse für die Erzeugung der notwendigen Objekte(Normale oder spezielle Verpackung und normaler Versand oder per Kurier).

AbstractProduct (A/B):
Abstrakte Klasse für die Produkte die die Fabriken erzeugen können.

ConcreteProduct (A/B):
Die konkreten Produkte (Normale Verpackung/Normaler Versand,Normale Verpackung/Kurier,Spezielle Verpackung/Normaler Versand, Spezielle Verpackug/Kurier)
Nur mal als Beispiel:
CPA1:Normale Verpackung
CPA2:Normaler Versand
CPB1:Spezielle Verpackung
CPB2:Kurier

Code:
Code:
public class Client

{
    private AbstractProductA productA;
    private AbstractProductB productB;

    public Client(AbstractFactory factory)
   {
      productA = factory.CreateProductA();
      productB = factory.CreateProductB();
   }

}


public abstract class AbstractFactory
{
   public abstract AbstractProductA CreateProductA();
   public abstract AbstractProductB CreateProductB();
}

public class ConcreteFactoryA extends AbstractFactory
{
   @Override
   public AbstractProductA CreateProductA()
   {return new ProductA1();}


   @Override
   public AbstractProductB CreateProductB()
   {return new ProductB1();}
}

public class ConcreteFactoryB extends AbstractFactory
{
   @Override
   public AbstractProductA CreateProductA()
   {return new ProductA2();}

   @Override
   public AbstractProductB CreateProductB()
   {return new ProductB2();}
}

public abstract class AbstractProductA { }
public class ProductA1 extends AbstractProductA { }
public class ProductA2 extends AbstractProductA { }
public abstract class AbstractProductB { }
public class ProductB1 extends AbstractProductB { }
public class ProductB2 extends AbstractProductB { }

Builder Pattern
Definition:
Wie die Abstract Factory dient das Builder Pattern zur Klasseninstanzierungs, gehört somit auch zur Unterkategorie der "Class Creational Pattern". Es dient dazu komplexe Objekte mit einzelnen Bestandteilen zu kreieren die optional sind und/oder die Reihenfolge beim initialisieren der Eigenschaften eines Objektes eine Rolle spielen. Vor dem Pattern hat man dazu unterschiedliche Konstruktoren schreiben müssen. Es hilft vor allem Konstruktoren mit unendlich langen Parameterlisten zu vermeiden. Eine Klasse die oftmals "Director" genannt wird handelt die Erstellung dieser Objekte. Beliebt sind auch eine innere statische Klasse die einfach nur Builder genannt werden (siehe zum Beispiel die SoundPool API von Android uvm. Das 2. Codebeispiel ist so eine Implementierung)


Beispiel:
Nehmen wir an wir sind in einem Schnellimbiss. Dort werden unterschiedliche Gerichte zubereitet. Dazu gibt es unterschiedliche Beilagen und Getränke. Zum Beispiel kann man sich einen Hamburger oder einen Cheeseburger bestellen. Dazu kann man entweder Pommes oder Salat wünschen und eine Cola oder eine Sprite. Wie die Gerichte zusammengestellt werden bleibt immer gleich und sollte in der gleichen Reihenfolge geschehen.

Builder.png


Product:
Die Produktklasse definiert den Typus des Objektes, das generiert werden soll.

Builder:
Diese abstrakte Klasse definiert die Schritte die gegangen werden müssen um das Objekt zu kreieren. In den Subklassen werden diese Schritte dann implementiert. Die GetProduct()- Methode dient dazu das fertige Objekt zurückzugeben(Oftmals auch einfach als Build() bezeichnet)

ConcreteBuilder:
Diese Klasse implementiert die eigentlichen Operationen die getan werden müssen.

Director:
Der Direktor kontrolliert den Algorithmus um die Objekte zu erzeugen. Wenn ein Director instanziert wird wird sein Konstruktor aufgerufen. Dieser nimmt als Parameter ein Builderobjekt oder abgeleitete Klassenobjekte. Dieses Objekt wird benutzt um die eigentlichen Schritte in der richtigen Reihenfolge durchzuführen. Am ende kann mann dann mit der GetProduct()- Methode eine Instanz des Produktes bekommen.


Code:
Code:
public class Director
{
   public void Construct(Builder builder)
   {
      builder.BuildPart1();
      builder.BuildPart2();
      builder.BuildPart3();
   }
}

public abstract class Builder
{
   public abstract void BuildPart1();
   public abstract void BuildPart2();
   public abstract void BuildPart3();
   public abstract Product Build();
}

public class ConcreteBuilder extends Builder
{
   private Product product = new Product();

   @Override
   public void BuildPart1()
   {product.Part1 = "Part 1";}

   @Override
   public override void BuildPart2()
   {product.Part2 = "Part 2";}

   @Override
   public override void BuildPart3()
   {product.Part3 = "Part 3";}

   @Override
   public override Product Build()
   {return product;}
}

public class Product
{
   public string Part1;
   public string Part2;
   public string Part3;
}

Code with nested static class:
Code:
public class Person
{
   private final String lastName;
   private final String firstName;
   private final String streetAddress;

   public Person( final String newLastName, final String newFirstName,
                         final String newStreetAddress)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.streetAddress = newStreetAddress;
   }

   public static class PersonBuilder
   {
      private String nestedLastName;
      private String nestedFirstName;
      private String nestedStreetAddress;

      public PersonBuilder(final String newFirstName)
      {this.nestedFirstName = newFirstName;}

      public PersonBuilder lastName(String newLastName)
      {
         this.nestedLastName = newLastName;
         return this;
      }

      public PersonBuilder firstName(String newFirstName)
      {
         this.nestedFirstName = newFirstName;
         return this;
      }

      public PersonBuilder streetAddress(String newStreetAddress)
      {
         this.nestedStreetAddress = newStreetAddress;
         return this;
      }

      public Person createPerson()
      {return new Person( nestedLastName, nestedFirstName, nestedStreetAddress);}
   }
}

Factory Method Pattern
Definition:
Dieses Muster wird benutzt um Konstruktoren zu ersetzen, die Objektinstanzierung zu abstrahieren und zwar so, dass der Typ des zu instanzierenden Objektes erst zur Laufzeit ermittelt werden kann.


Beispiel:
Ein Beispiel wäre zum Beispiel eine Verbindung zu einer Datenquelle aufzubauen. Diese kann vom Benutzer per User Interface zur Laufzeit ausgewählt werden. In diesem Fall könnte eine abstrakte Klasse "Datenquelle" erstellt werden, welches die Grundeigenschaft aller Datenquellen schonmal festlegt. Man könnte jetzt einige Subklassen erstellen wie zum Beispiel "XMLDatenQuelle" oder SQLDatenQuelle" oder "CSVDatenQuelle". Zur LAufzeit könnte eine Klasse "DatenQuellenFabrik" die richtige Unterklasse von "DatenQuelle" instanzieren und so auf die jeweilige ausgesuchte Datenquelle zugreifen.

FactoryMethod.png



FactoryBase:
Abstrakte Oberklasse für "ConcreteFactory"

ConcreteFactory:
Leiten von "FactoryBase" ab. Überschreibt die Methoden der Basisklasse, um die einzelnen Objekte herzustellen.

ProductBase:
Abstrakte Klasse für die Objekte die eine konkrete Fabrik herstellen kann. Dient ebenfalls als Rückgabetyp für die Methoden der Fabriken.

ConcreteProduct:
Das sind die konkreten Klassen die eine Fabrik erstellen kann. Jedes definiert ihre eigenen Funktionalitäten.

Code:
Code:
public abstract class FactoryBase
{
    public abstract ProductBase FactoryMethod (int type);
}


public class ConcreteFactory extends FactoryBase
{
   @Override
   public ProductBase FactoryMethod(int type)
   {
      switch (type)
      {
         case 1: return new ConcreteProduct1();
         case 2: return new ConcreteProduct2();
         default: return null;
      }
   }
}

public abstract class ProductBase { }

public class ConcreteProduct1 extends ProductBase { }

public class ConcreteProduct2 extends ProductBase { }

Prototype Pattern
Definition:

Dieses Muster wird benutzt, um ein neues Objekt zu instanzieren indem es ein vorhandes Objekt mit allen Eigenschaften kopiert und somit einen unabhängigen Klon erstellt. Nützlich wenn die Konstruktion eines neuen Objektes mit dem new operator ineffizient wäre.

Beispiel:


Prototype.png



Prototype:
Eine abstrakte Klasse für alle Objekte die generiert und geklont werden können. Diese Klasse enthält eine Clone()-Methode die ein Prototype als Rückgabetyp hat.

ConcretePrototype (A/B):
Diese Klassen leiten von Prototype ab und enthalten alle notwendigen zusätzlichen Funktionalitäten und Eigenschaften. Diese Unterklassen überschreiben die Clone() Methode um das Duplizieren ihrer Eigenschaften zu deklarieren.

Code:
Code:
public abstract class Prototype implements Cloneable
{
   public abstract Prototype clone();
}

public class ConcretePrototypeA extends Prototype
{
   @Override
   public Prototype clone()
   {
      return super.clone();
   }
}

public class ConcretePrototypeB extends Prototype
{
   @Override
   public Prototype clone()
   {
      return super.clone();
   }
}

Singleton Pattern
Definition:
Das Sigleton Pattern wird benutzt um sicherzustellen dass nur ein einziges Objekt einer Klasse zur gleichen Zeit besteht. Alle Referenzen auf eine Klasseninstanz beziehen sich auf ein und dasselbe Objekt,
Es ist besser ein Singleton zu besitzen als eine globale Variable da diese kopiert werden kann und unterschiedliche Kopien zu fehlerhaften Ergebnissen führen können.

Beispiel:

Singleton.png


Das Singleton stellt eine statische Methode dar um eine einzelne Instanz der Klasse zu generieren. Der Konstruktor dieser Klasse ist als private deklariert um eine Instanzierung von ausserhalb zu verhindern.
Üblicherweise wird ein Singleton erst dann kreiert wenn es benötigt wird.
Die Klasse ist ebenfalls so angelegt dass keine andere Klasse von ihr erben kann.

Als Beispiel kann man eine Datenbankverbindung nehmen. Eine Datenbankverbindung sollte nur solange es nötig ist offen sein bzw. sollte es nur ein Objekt geben dass auf eine Datenbank zur gleichen Zeit Zugriff hat um Datenkorrupmtion zu vermeiden.

Code (Java):
Code:
public final class Singleton
{
   private static Singleton instance;

   private Singleton ()
   {}

   public static Singleton getSingleton ()
   {
      if (Singleton.instance == null)
      {
         Singleton.instance = new Singleton ();
      }
      return Singleton.instance;
   }
}

Code (Java) Threadsafe:
Code:
public final class Singleton
{
   private static Singleton instance;

   private Singleton ()
   {}

   public static synchronized Singleton getSingleton ()
   {
      if (Singleton.instance == null)
      {
         Singleton.instance = new Singleton ();
      }
      return Singleton.instance;
   }
}

Code (Java) implicitly Threadsafe:
Code:
public final class Singleton
{
   private static final class InstanceHolder
   {
      static final Singleton INSTANCE = new Singleton();
   }

   private Singleton ()
   {}

   public static Singleton getSingleton ()
   {
      return InstanceHolder.INSTANCE;
   }
}

Anmerkung für die Android programmierung:
Das Singleton Pattern ist mit Vorsicht zu genießen. Nicht selten kommt es vor dass statische Variablen/Objekte auf 0/null gesetzt werden falls ein Prozess vom System gekillt wird. Von daher sollte man Sicherheitsmechanismen einbauen um zu gewährleisten, dass der Status des Singleton in Ordnung ist und nicht zu Fehler oder Abstürzen führt.
Darüber hinaus lebt ein Singleton über Activities hinaus weiter bis die App geschlossen und der Prozess angehalten wird.
Es gilt oftmals auch als Antipattern, da wenn man nicht aufpasst es zu sehr schwer zu debuggenden Code führen kann und dadurch mehr Probleme verursacht als es hilft. Man sollte aufpassen es Threadsicher zu gestalten(wie die letzten beiden Code Beispiele zeigen), da auf eine Instanz von mehreren Stellen im Programm gleichzeitig zugegriffen werden kann.
Auch verstößt das Singleton generell gegen die Prinzipien des objektorientierten Programmieren, aber das tut Java ja schon von Grundauf also whatever :).

Genießt es mit Vorsicht und wägt immer ab ob es der richtige Ansatz ist gegenüber globalen Membern/Objekten zum Beispiel.
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: burgerohnealles und Kardroid
Wenn du das selbe auch noch zu "Structural Patterns" und "Behavioural Patterns" posten könntest, wäres das echt MEGA NICE :)
 
Jo klar Studium steht gerade im Weg etwas :D Aber wird Fortgeführt auf jeden Fall...
 

Ähnliche Themen

H
  • HerrFatalVonError
Antworten
10
Aufrufe
1.256
HerrFatalVonError
H
A
Antworten
0
Aufrufe
736
Arif12
A
Zurück
Oben Unten