3.1 Singleton

Singleton ist ein generisches Entwurfsmuster, das garantiert, dass eine Single-Thread-Anwendung über eine einzelne Instanz einer Klasse verfügt, und einen globalen Zugriffspunkt auf diese Instanz bereitstellt.

Singleton

Sehr oft möchten unerfahrene Programmierer Dienstprogrammmethoden in einer statischen Klasse zusammenfassen – einer Klasse, die nur statische Methoden enthält. Dieser Ansatz hat eine Reihe von Nachteilen: Sie können beispielsweise keine Referenz auf ein Objekt einer solchen Klasse übergeben, solche Methoden sind schwierig zu testen und dergleichen.

Als Alternative wurde eine Singleton-Klassenlösung vorgeschlagen: eine Klasse, die nur ein Objekt haben kann. Beim Versuch, dieses Objekt zu erstellen, wird es nur erstellt, wenn es noch nicht vorhanden ist, andernfalls wird ein Verweis auf eine bereits vorhandene Instanz zurückgegeben.

Es ist wichtig, dass eine Instanz der Klasse verwendet werden kann, da in vielen Fällen eine größere Funktionalität verfügbar wird. Diese Klasse kann beispielsweise einige Schnittstellen implementieren und ihr Objekt kann als Implementierung der Schnittstelle an andere Methoden übergeben werden. Was mit einer Reihe statischer Methoden nicht möglich ist.

Vorteile:

  • Methoden sind an ein Objekt gebunden, nicht an eine statische Klasse – Sie können ein Objekt als Referenz übergeben.
  • Objektmethoden sind viel einfacher zu testen und zu simulieren.
  • Ein Objekt wird nur bei Bedarf erstellt: Lazy Object Initialization.
  • Beschleunigung des ersten Starts des Programms, wenn es viele Singles gibt, die für den Start nicht benötigt werden.
  • Ein einzelnes oder mehrere solcher Objekte können weiter in eine Template-Strategie umgewandelt werden.

Nachteile:

  • Es wird schwieriger, Rennen und Verzögerungen zwischen Threads zu kontrollieren.
  • Es ist schwierig, einen Multithread-„Einzelgänger“ „aus dem Kopf“ zu schreiben: Der Zugriff auf einen langjährigen Singleton sollte im Idealfall keinen Mutex öffnen. Besser bewährte Lösungen.
  • Ein Konflikt zwischen zwei Threads über einen nicht abgeschlossenen einzelnen Thread führt zu einer Verzögerung.
  • Wenn das Objekt über einen längeren Zeitraum erstellt wird, kann die Verzögerung den Benutzer beeinträchtigen oder die Echtzeit stören. In diesem Fall ist es besser, die Erstellung in die Phase der Programminitialisierung zu verlagern.
  • Für Unit-Tests sind besondere Funktionen erforderlich – beispielsweise um die Bibliothek in den „nicht einsamen“ Modus zu versetzen und Tests vollständig voneinander zu isolieren.
  • Eine besondere Taktik zum Testen des fertigen Programms ist erforderlich, da sogar das Konzept der „einfachsten Startbarkeit“ verschwindet, da die Startbarkeit von der Konfiguration abhängt.

3.2 Fabrik [Methode]

Eine Factory-Methode ist ein generisches Entwurfsmuster, das Unterklassen (Klassen-Erben) eine Schnittstelle zum Erstellen von Instanzen einer bestimmten Klasse bereitstellt. Zum Zeitpunkt der Erstellung können Nachkommen bestimmen, welche Klasse erstellt werden soll.

Mit anderen Worten: Diese Vorlage delegiert die Erstellung von Objekten an die Nachkommen der übergeordneten Klasse. Dadurch können Sie nicht konkrete Klassen im Programmcode verwenden, sondern abstrakte Objekte auf einer höheren Ebene manipulieren.

Fabrikmethode

Dieses Muster definiert eine Schnittstelle zum Erstellen eines Objekts, überlässt es jedoch den Unterklassen, zu entscheiden, auf welcher Klasse das Objekt basieren soll. Eine Factory-Methode ermöglicht es einer Klasse, die Erstellung von Unterklassen zu delegieren. Wird verwendet, wenn:

  • Die Klasse weiß im Voraus nicht, welche Objekte welcher Unterklassen sie erstellen muss.
  • Eine Klasse ist so konzipiert, dass die von ihr erstellten Objekte durch Unterklassen spezifiziert werden.
  • Die Klasse delegiert ihre Verantwortlichkeiten an eine von mehreren Hilfsunterklassen, und es ist geplant, zu bestimmen, welche Klasse diese Verantwortlichkeiten übernimmt.

3.3 Abstrakte Fabrik

Eine abstrakte Fabrik ist ein generisches Entwurfsmuster, das eine Schnittstelle zum Erstellen von Familien verwandter oder voneinander abhängiger Objekte bereitstellt, ohne deren konkrete Klassen anzugeben.

Das Muster wird durch die Erstellung einer abstrakten Klasse Factory implementiert, die eine Schnittstelle zum Erstellen von Systemkomponenten darstellt (für eine Fensterschnittstelle können beispielsweise Fenster und Schaltflächen erstellt werden). Anschließend werden Klassen geschrieben, die diese Schnittstelle implementieren.

Abstrakte Fabrik

Es wird in Fällen verwendet, in denen das Programm unabhängig vom Prozess und den Typen der neu erstellten Objekte sein muss. Wenn es notwendig ist, Familien oder Gruppen verwandter Objekte zu erstellen, wobei die Möglichkeit der gleichzeitigen Verwendung von Objekten aus verschiedenen Gruppen dieser Objekte im selben Kontext ausgeschlossen ist.

Starke Seiten:

  • isoliert bestimmte Klassen;
  • vereinfacht den Austausch von Produktfamilien;
  • garantiert Produktkompatibilität.

Nehmen wir an, Ihr Programm arbeitet mit dem Dateisystem. Um unter Linux zu arbeiten, benötigen Sie dann die Objekte LinuxFile, LinuxDirectory und LinuxFileSystem. Und um in Windwos zu arbeiten, benötigen Sie die Klassen WindowsFile, WindowsDirectory und WindowsFileSystem.

Ein solcher Fall ist die Path-Klasse, die über Path.of() erstellt wird. Path ist eigentlich keine Klasse, sondern eine Schnittstelle und verfügt über WindowsPath- und LinuxPath-Implementierungen. Und welche Art von Objekt erstellt wird, bleibt Ihrem Code verborgen und wird zur Laufzeit entschieden.

3.4 Prototyp

Prototyp ist ein generatives Designmuster.

Dieses Muster definiert die Arten von Objekten, die mithilfe einer Prototypinstanz erstellt werden, und erstellt neue Objekte durch Kopieren dieses Prototyps. Es ermöglicht Ihnen, sich von der Implementierung zu lösen und dem Prinzip der „Programmierung durch Schnittstellen“ zu folgen.

Als Rückgabetyp wird eine Schnittstelle/abstrakte Klasse an der Spitze der Hierarchie angegeben, und Nachkommenklassen können einen Erben ersetzen, der diesen Typ dort implementiert. Einfach ausgedrückt ist dies das Muster, bei dem ein Objekt durch Klonen eines anderen Objekts erstellt wird, anstatt es über einen Konstruktor zu erstellen.

Prototyp

Das Muster wird verwendet für:

  • Vermeidung des zusätzlichen Aufwands, ein Objekt auf standardmäßige Weise zu erstellen (d. h. unter Verwendung eines Konstruktors, da in diesem Fall auch die Konstruktoren der gesamten Vorgängerhierarchie des Objekts aufgerufen werden), wenn dies für die Anwendung unerschwinglich ist.
  • Vermeiden Sie es, den Objektersteller in der Clientanwendung zu erben, wie dies beim abstrakten Factory-Muster der Fall ist.

Verwenden Sie dieses Entwurfsmuster, wenn es Ihrem Programm egal ist, wie es Produkte erstellt, zusammenstellt und präsentiert:

  • instanziierte Klassen werden zur Laufzeit ermittelt, beispielsweise durch dynamisches Laden;
  • Sie möchten vermeiden, Klassen- oder Fabrikhierarchien zu erstellen, die der Produktklassenhierarchie entsprechen.
  • Klasseninstanzen können sich in einem von mehreren unterschiedlichen Zuständen befinden. Es kann bequemer sein, die entsprechende Anzahl von Prototypen festzulegen und diese zu klonen, als die Klasse jedes Mal manuell im entsprechenden Zustand zu instanziieren.