Java-Designmuster – Beispiel-Tutorial

Einführung

Design Patterns sind sehr beliebt bei Softwareentwicklern. Ein Design Pattern ist eine gut beschriebene Lösung für ein häufig auftretendes Softwareproblem.

Einige Vorteile der Verwendung von Design Patterns sind:

  1. Design Patterns sind bereits definiert und bieten einen Branchenstandard-Ansatz zur Lösung eines wiederkehrenden Problems, daher spart es Zeit, wenn wir das Design Pattern vernünftig verwenden. Es gibt viele Java Design Patterns, die wir in unseren Java-basierten Projekten verwenden können.
  2. Die Verwendung von Design Patterns fördert die Wiederverwendbarkeit, was zu einem robusteren und hoch wartbaren Code führt. Es hilft dabei, die Gesamtbetriebskosten (TCO) des Softwareprodukts zu reduzieren.
  3. Da Design Patterns bereits definiert sind, wird unser Code leicht verständlich und debugbar. Es führt zu schnellerer Entwicklung und neue Teammitglieder können es leicht verstehen.

Java Design Patterns sind in drei Kategorien unterteilt – Erzeugungsmuster, Strukturmuster und Verhaltensmuster.

Dieser Artikel dient als Index für alle Java Design Pattern Artikel.

Erzeugungsmuster

Die Erzeugungsmuster bieten Lösungen für die Instanziierung eines Objekts auf die bestmögliche Weise für spezifische Situationen.

1. Singleton-Muster

Das Singleton-Muster beschränkt die Instanziierung einer Klasse und stellt sicher, dass nur eine Instanz der Klasse in der Java Virtual Machine existiert. Die Implementierung des Singleton-Musters war schon immer ein umstrittenes Thema unter Entwicklern.

Hinweis: Erfahren Sie mehr über das Singleton-Entwurfsmuster.

2. Fabrikmuster

Das Fabrikmuster wird verwendet, wenn wir eine Superklasse mit mehreren Unterklassen haben und basierend auf der Eingabe eine der Unterklassen zurückgeben müssen. Dieses Muster entlastet das Client-Programm von der Verantwortung für die Instanziierung einer Klasse und überträgt sie auf die Fabrikklasse. Wir können das Singleton-Muster auf die Fabrikklasse anwenden oder die Fabrikmethode static machen.

Hinweis: Erfahren Sie mehr über das Fabrik-Entwurfsmuster.

3. Abstract Factory Pattern

Das abstrakte Fabrikmuster ähnelt dem Fabrikmuster und ist eine Fabrik von Fabriken. Wenn Sie mit dem Fabrik-Entwurfsmuster in Java vertraut sind, werden Sie feststellen, dass wir eine einzige Fabrikklasse haben, die auf der Grundlage der bereitgestellten Eingabe und der Fabrikklassen if-else– oder switch-Anweisungen die verschiedenen Unterklassen zurückgibt. Beim abstrakten Fabrikmuster eliminieren wir den if-else-Block und haben für jede Unterklasse eine eigene Fabrikklasse sowie eine abstrakte Fabrikklasse, die die Unterklassen auf der Grundlage der Eingabefabrikklassen zurückgibt.

Hinweis: Erfahren Sie mehr über das abstrakte Fabrikmuster.

4. Builder Pattern

Das Builder-Muster wurde eingeführt, um einige Probleme mit den Fabrik- und abstrakten Fabrikmustern zu lösen, wenn das Objekt viele Attribute enthält. Dieses Muster löst das Problem mit einer großen Anzahl optionaler Parameter und einem inkonsistenten Zustand, indem es eine Möglichkeit bietet, das Objekt schrittweise aufzubauen und eine Methode bereitzustellen, die das endgültige Objekt zurückgibt.

Hinweis: Erfahren Sie mehr über das Builder-Muster.

5. Prototyp-Muster

Das Prototyp-Muster wird verwendet, wenn die Erstellung des Objekts kostspielig ist und viel Zeit und Ressourcen erfordert, und Sie bereits ein ähnliches Objekt haben. Dieses Muster bietet daher einen Mechanismus zum Kopieren des Original-Objekts in ein neues Objekt und anschließendes Ändern entsprechend unseren Bedürfnissen. Dieses Muster verwendet das Klonen in Java, um das Objekt zu kopieren. Das Prototyp-Entwurfsmuster schreibt vor, dass das zu kopierende Objekt die Kopierfunktion bereitstellen sollte. Dies sollte nicht von einer anderen Klasse durchgeführt werden. Allerdings hängt es davon ab, ob eine flache oder tiefe Kopie der Objekteigenschaften verwendet wird, abhängig von den Anforderungen und ist eine Designentscheidung.

Hinweis: Erfahren Sie mehr über das Prototyp-Muster.

Strukturelle Entwurfsmuster

Strukturmuster bieten verschiedene Möglichkeiten, eine Klassenstruktur zu erstellen (zum Beispiel durch Vererbung und Komposition, um ein großes Objekt aus kleinen Objekten zu erstellen).

1. Adapter-Muster

Das Adapter-Entwurfsmuster ist eines der strukturellen Entwurfsmuster und wird verwendet, damit zwei nicht verwandte Schnittstellen zusammenarbeiten können. Das Objekt, das diese nicht verwandten Schnittstellen verbindet, wird als Adapter bezeichnet.

Hinweis: Erfahren Sie mehr über das Adapter-Muster.

2. Komposit-Muster

Das Kompositmuster wird verwendet, wenn wir eine Teil-Ganzes-Hierarchie darstellen müssen. Wenn wir eine Struktur erstellen müssen, bei der die Objekte in der Struktur gleich behandelt werden müssen, können wir das Kompositentwurfsmuster anwenden.

Hinweis: Erfahren Sie mehr über das Komposit-Muster.

3. Proxy-Muster

Das Proxy-Muster bietet einen Platzhalter für ein anderes Objekt, um den Zugriff darauf zu kontrollieren. Dieses Muster wird verwendet, wenn wir einen kontrollierten Zugriff auf Funktionalität bereitstellen möchten.

Hinweis: Erfahren Sie mehr über das Proxy-Muster.

4. Flyweight-Muster

Das Flyweight-Entwurfsmuster wird verwendet, wenn wir viele Objekte einer Klasse erstellen müssen. Da jedes Objekt Speicherplatz verbraucht, der für Speichergeräte mit geringem Speicherplatz (wie Mobilgeräte oder eingebettete Systeme) entscheidend sein kann, kann das Flyweight-Entwurfsmuster angewendet werden, um die Speicherlast durch gemeinsame Nutzung von Objekten zu reduzieren.

Die Implementierung des String-Pools in Java ist eines der besten Beispiele für die Implementierung des Flyweight-Musters.

Hinweis: Erfahren Sie mehr über das Flyweight-Muster.

5. Fassadenmuster

Das Fassadenmuster wird verwendet, um Client-Anwendungen dabei zu helfen, leicht mit dem System zu interagieren.

Hinweis: Erfahren Sie mehr über das Fassadenmuster.

6. Brückenmuster

Wenn wir Schnittstellenhierarchien sowohl in Schnittstellen als auch in Implementierungen haben, wird das Brücken-Entwurfsmuster verwendet, um die Schnittstellen von der Implementierung zu entkoppeln und die Implementierungsdetails vor den Client-Programmen zu verbergen. Die Implementierung des Brücken-Entwurfsmusters folgt dem Grundsatz, Komposition vor Vererbung zu bevorzugen.

Hinweis: Erfahren Sie mehr über das Brückenmuster.

7. Dekorierermuster

Der Decorator-Entwurfsmuster wird verwendet, um die Funktionalität eines Objekts zur Laufzeit zu modifizieren. Dabei werden andere Instanzen derselben Klasse nicht beeinflusst, sodass das individuelle Objekt das geänderte Verhalten erhält. Das Decorator-Entwurfsmuster gehört zu den strukturellen Entwurfsmustern (wie Adaptermuster, Brückenmuster oder Kompositenmuster) und verwendet abstrakte Klassen oder Schnittstellen mit Komposition zur Implementierung. Wir verwenden Vererbung oder Komposition, um das Verhalten eines Objekts zu erweitern, jedoch geschieht dies zur Kompilierzeit und gilt für alle Instanzen der Klasse. Es ist nicht möglich, zur Laufzeit neue Funktionalitäten hinzuzufügen oder bestehendes Verhalten zu entfernen – hier kommt das Decorator-Muster zum Einsatz.

Hinweis: Erfahren Sie mehr über das Decorator Pattern.

Verhaltensmuster

Verhaltensmuster bieten eine Lösung für eine bessere Interaktion zwischen Objekten und wie eine lose Kopplung sowie Flexibilität zur einfachen Erweiterung bereitgestellt werden können.

1. Vorlagenmethodenmuster

Die Vorlagenmethode ist ein Verhaltensmuster und wird verwendet, um eine Methodenvorlage zu erstellen und einige der Implementierungsschritte an die Unterklassen zu verschieben. Die Vorlagenmethode definiert die Schritte zur Ausführung eines Algorithmus und kann eine Standardimplementierung bereitstellen, die für alle oder einige der Unterklassen gemeinsam sein kann.

Hinweis: Erfahren Sie mehr über das Vorlagenmethodenmuster.

2. Mediator-Muster

Das Mediator-Entwurfsmuster wird verwendet, um ein zentrales Kommunikationsmedium zwischen verschiedenen Objekten in einem System bereitzustellen. Wenn die Objekte direkt miteinander interagieren, sind die Systemkomponenten eng miteinander gekoppelt, was die Wartungskosten erhöht und eine einfache Erweiterung erschwert. Das Mediator-Muster konzentriert sich darauf, einen Mediator zwischen Objekten für die Kommunikation bereitzustellen und eine lose Kopplung zwischen den Objekten zu implementieren. Der Mediator fungiert als Router zwischen Objekten und kann über eigene Logik verfügen, um eine Kommunikationsmöglichkeit zu bieten.

Hinweis: Erfahren Sie mehr über das Mediator-Muster.

3. Chain of Responsibility Pattern

Das Chain-of-Responsibility-Muster wird verwendet, um eine lose Kopplung im Software-Design zu erreichen, bei dem eine Anforderung des Clients an eine Kette von Objekten übergeben wird, um sie zu verarbeiten. Dann entscheidet das Objekt in der Kette, wer die Anforderung verarbeiten wird und ob die Anforderung an das nächste Objekt in der Kette gesendet werden muss oder nicht.

Wir wissen, dass wir mehrere catch-Blöcke in einem try-catch-Block haben können. Jeder catch-Block ist eine Art Prozessor, um diese bestimmte Ausnahme zu verarbeiten. Wenn also eine Ausnahme im try-Block auftritt, wird sie an den ersten catch-Block gesendet, um sie zu verarbeiten. Wenn der catch-Block sie nicht verarbeiten kann, leitet er die Anforderung an das nächste Objekt in der Kette weiter (d. h. an den nächsten catch-Block). Wenn selbst der letzte catch-Block sie nicht verarbeiten kann, wird die Ausnahme außerhalb der Kette an das aufrufende Programm geworfen.

Hinweis: Erfahren Sie mehr über das Chain-of-Responsibility-Muster.

4. Observer Pattern

Ein Beobachter-Entwurfsmuster ist nützlich, wenn Sie am Zustand eines Objekts interessiert sind und benachrichtigt werden möchten, sobald sich etwas ändert. Im Beobachtermuster wird das Objekt, das den Zustand eines anderen Objekts überwacht, als Beobachter bezeichnet, und das Objekt, das beobachtet wird, als Subjekt.

Java bietet eine integrierte Plattform zur Implementierung des Beobachtermusters über die Klasse java.util.Observable und das Interface java.util.Observer. Es wird jedoch nicht weit verbreitet verwendet, da die Implementierung eingeschränkt ist und wir in der Regel nicht wollen, dass wir nur zum Implementieren des Beobachtermusters eine Klasse erweitern, da Java keine Mehrfachvererbung in Klassen bietet. Java Message Service (JMS) verwendet das Beobachtermuster zusammen mit dem Vermittlermuster, um Anwendungen zu ermöglichen, Daten zu abonnieren und an andere Anwendungen zu senden.

Hinweis: Erfahren Sie mehr über das Beobachtermuster.

5. Strategiemuster

Das Strategiemuster wird verwendet, wenn wir mehrere Algorithmen für eine bestimmte Aufgabe haben und der Client entscheidet, welche tatsächliche Implementierung zur Laufzeit verwendet werden soll. Ein Strategiemuster wird auch als Richtlinienmuster bezeichnet. Wir definieren mehrere Algorithmen und lassen Clientanwendungen den Algorithmus als Parameter übergeben.

Eine der besten Beispiele für dieses Muster ist die Methode Collections.sort(), die den Comparator-Parameter verwendet. Basierend auf den verschiedenen Implementierungen von Comparator-Schnittstellen werden die Objekte auf unterschiedliche Weise sortiert.

Hinweis: Erfahren Sie mehr über das Strategiemuster.

6. Befehlsmuster

Das Befehlsmuster wird verwendet, um Loose-Coupling in einem Anfrage-Antwort-Modell umzusetzen. In diesem Muster wird die Anfrage an den Invoker gesendet, und der Invoker leitet sie an das gekapselte Command-Objekt weiter. Das Command-Objekt leitet die Anfrage an die entsprechende Methode des Empfängers weiter, um die spezifische Aktion auszuführen.

Hinweis: Erfahren Sie mehr über das Befehlsmuster.

7. Zustandsmuster

Der Zustandsentwurf wird verwendet, wenn ein Objekt sein Verhalten basierend auf seinem internen Zustand ändert. Wenn wir das Verhalten eines Objekts basierend auf seinem Zustand ändern müssen, können wir eine Zustandsvariable im Objekt haben und einen if-else-Bedingungsblock verwenden, um unterschiedliche Aktionen basierend auf dem Zustand auszuführen. Das Zustandsmuster wird verwendet, um dies systematisch und locker gekoppelt durch Kontext- und Zustandsimplementierungen zu erreichen.

Hinweis: Erfahren Sie mehr über das Zustandsmuster.

8. Besucher-Muster

Das Besucher-Muster wird verwendet, wenn wir eine Operation auf einer Gruppe ähnlicher Objekte durchführen müssen. Mit Hilfe eines Besucher-Musters können wir die operationale Logik von den Objekten in eine andere Klasse verschieben.

Hinweis: Erfahren Sie mehr über das Besucher-Muster.

9. Interpreter-Muster

Das Interpreter-Muster wird verwendet, um eine grammatische Darstellung einer Sprache zu definieren und einen Interpreter bereitzustellen, um mit dieser Grammatik umzugehen.

10. Iterator-Muster

Das Iterator-Muster ist eines der Verhaltensmuster und wird verwendet, um eine standardisierte Möglichkeit zum Durchlaufen einer Gruppe von Objekten bereitzustellen. Das Iterator-Muster wird weitgehend in Java Collection Framework eingesetzt, wobei das Iterator-Interface Methoden zum Durchlaufen einer Collection bereitstellt. Dieses Muster wird auch verwendet, um verschiedene Arten von Iteratoren basierend auf unseren Anforderungen bereitzustellen. Das Iterator-Muster verbirgt die tatsächliche Implementierung des Durchlaufs durch die Collection, und Client-Programme verwenden Iterator-Methoden.

Hinweis: Erfahren Sie mehr über das Iterator-Muster.

11. Memento-Muster

Das Memento-Entwurfsmuster wird verwendet, wenn wir den Zustand eines Objekts speichern möchten, um ihn später wiederherstellen zu können. Dieses Muster wird so implementiert, dass die gespeicherten Zustandsdaten des Objekts außerhalb des Objekts nicht zugänglich sind, um die Integrität der gespeicherten Zustandsdaten zu schützen.

Das Memento-Muster wird mit zwei Objects implementiert – Originator und Caretaker. Der Originator ist das Object, dessen Zustand gespeichert und wiederhergestellt werden muss, und es verwendet eine innere Klasse, um den Zustand des Object zu speichern. Die innere Klasse heißt „Memento“ und ist private, damit sie nicht von anderen Objekten aus zugegriffen werden kann.

Unterschiedliche Entwurfsmuster

Es gibt viele Entwurfsmuster, die nicht unter die Gang-of-Four-Entwurfsmuster fallen. Lassen Sie uns einige dieser beliebten Entwurfsmuster betrachten.

1. DAO-Entwurfsmuster

Das Data Access Object (DAO)-Entwurfsmuster wird verwendet, um die Datenpersistenzlogik in eine separate Schicht zu entkoppeln. DAO ist ein sehr beliebtes Muster, wenn wir Systeme entwerfen, die mit Datenbanken arbeiten. Die Idee besteht darin, die Servicesschicht von der Datenaufgriffschicht zu trennen. Auf diese Weise implementieren wir die Trennung der Logik in unserer Anwendung.

Hinweis: Erfahren Sie mehr über das DAO-Muster.

2. Dependency Injection Pattern

Das Dependency Injection-Muster ermöglicht es uns, die festcodierten Abhängigkeiten zu entfernen und unsere Anwendung locker gekoppelt, erweiterbar und wartbar zu machen. Wir können Dependency Injection in Java implementieren, um die Abhängigkeitsauflösung von der Kompilierungszeit auf die Laufzeit zu verschieben. Das Spring-Framework basiert auf dem Prinzip der Dependency Injection.

Hinweis: Erfahren Sie mehr über das Dependency Injection-Muster.

3. MVC-Muster

Das Model-View-Controller (MVC)-Muster ist eines der ältesten architektonischen Muster zur Erstellung von Webanwendungen.

Zusammenfassung

Dieser Artikel fasst Java-Entwurfsmuster zusammen.

Sie können Beispielcode für Java-Entwurfsmuster aus unserem GitHub-Repository überprüfen.

Machen Sie Ihr Lernen mit weiteren Java-Tutorials fort.

Source:
https://www.digitalocean.com/community/tutorials/java-design-patterns-example-tutorial