Entwurfsmuster sind spezifische Lösungsmuster (Routinen), die für bestimmte Probleme in bestimmten Situationen, die ständig auftreten, wiederverwendet werden können. Dieser Artikel fasst die wichtigsten Punkte der Verwendung von 24 gängigen Entwurfsmustern gemäß den drei Kategorien Erstellung, Struktur und Verhalten zusammen, einschließlich anwendbarer Szenarien, Lösungen und ihrer entsprechenden Java-Implementierungen.
Entwurfsmuster ist für ein bestimmtes „Problem“ in einem bestimmten „Kontext“, der ständig auftaucht. :
Das „Problem“ muss wiederkehrend sein und die „Lösung“ muss wiederholt anwendbar sein
„Problem“ enthält „ein Ziel“ und „eine Reihe von Einschränkungen“. Wenn die Lösung ein Gleichgewicht zwischen beiden herstellt, ist es ein nützliches Muster.
Entwurfsmuster sind keine Gesetze. Passen Sie sie nach Bedarf an, damit andere sie verstehen können.
Es sollte nie mehr als einen Grund für eine Klassenänderung geben. Eine Klasse hat nur eine einzige Verantwortung mehrere Verantwortlichkeiten in einer Klasse gekoppelt (z. B. sollten Schnittstelle und Logik getrennt werden).
Software-Entitäten wie Klassen, Module und Funktionen sollten für Erweiterungen offen, aber für Änderungen geschlossen sein.
Offen für Erweiterungen, geschlossen für Änderungen Schnittstellen und abstrakte Klassen.
Funktionen, die Zeiger oder Referenzen auf Basisklassen verwenden, müssen in der Lage sein, Objekte abgeleiteter Klassen zu verwenden, ohne zu wissen, wo die übergeordnete Klasse erscheinen kann , die Unterklasse kann definitiv erscheinen. Dies ist der Grundstein für Vererbung und Wiederverwendung.
Geringe Abhängigkeit, jede Entität ist so unabhängig wie möglich und interagiert mit so wenig wie möglich.
Der Client sollte nicht davon abhängig sein, dass er die Methode nicht verwendet . Versuchen Sie, mehrere Schnittstellen zu verwenden, um Funktionen aufzuteilen und zu kombinieren, anstatt mehrere Funktionen mit einer einzigen Schnittstelle zu koppeln.
Beide sollten von Abstraktionen abhängen. Abstraktionen sollten nicht von Details abhängen .
Abhängig von der Abstraktion (Schnittstelle oder abstrakte Klasse), nicht von der Konkretheit (konkrete Klasse).
Design Pattern ist eine Reihe klassifizierter und katalogisierter Code-Design-Erfahrungen, die wiederholt verwendet werden und den meisten Menschen bekannt sind. Der Zweck der Verwendung von Entwurfsmustern besteht darin, Code wiederzuverwenden, ihn für andere verständlicher zu machen und die Zuverlässigkeit des Codes sicherzustellen.
Entwurfsmuster verkomplizieren scheinbar einfache Probleme. Das „einfache“ Design weist jedoch eine geringe Flexibilität auf, lässt sich im aktuellen Projekt nur schwer erweitern und kann nicht in anderen Projekten verwendet werden, was einem „Einmalcode“ entspricht. Der Code des Entwurfsmusters ist klar strukturiert und lässt sich im aktuellen Projekt leicht erweitern. Er ist auch auf andere Projekte anwendbar und stellt ein universelles Design dar.
Nachdem sie Designmustern ausgesetzt wurden, haben viele Programmierer das Gefühl, dass sie wiedergeboren wurden und eine neue Ebene erreicht haben. Designmuster können als Standard für die Einteilung der Programmierebenen verwendet werden.
Jedes Designmuster impliziert mehrere OO-Prinzipien. Wenn es kein geeignetes Designmuster zur Auswahl gibt, können Sie zu den OO-Prinzipien zurückkehren Wahl;
(2) Die Verwendung von Mustern zur Beobachtung von Softwaresystemen kann auf der Entwurfsebene bleiben, ohne an trivialen Objektdetails festzuhalten; Nicht leicht missverstanden.
1.5 Wichtige Bücher
Autor: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, später bekannt als „Gang“ of Four, GoF). Es gibt zwei Bücher:
Sehr empfehlenswerte Lektüre. Der englische Titel lautet „Head First Design Patterns“.
Jeder, der an Jesus glaubt, muss die Bibel lesen, und jeder, der an OO (objektorientiert) glaubt, muss „Head First Design Patterns“ von the foursome, der offiziellen Website Head First Design Patterns, lesen. 2004 Das Buch gewann den Jolt Award (ähnlich den Oscars im Filmbereich).
ist der Held, der zum ersten Mal Muster klassifizierte und damit einen großen Sprung nach vorne im Softwarebereich startete
Mustervorlage: einschließlich Name , Klassenzweck, Absicht, Motivation, Anwendbarkeit, Klassendiagramm, Teilnehmer und ihre Zusammenarbeit, Ergebnisse, Implementierung, Beispielcode, bekannte Anwendungen, verwandte Muster usw.
Der englische Titel lautet „Design Patterns: Elemente wiederverwendbarer objektorientierter Software“ . Auch vom Quartett geschrieben.
ist ein Buch über Software-Design im Bereich Software-Engineering. Es schlägt Standardlösungen für einige häufige Software-Design-Probleme vor, die als Software-Design-Muster bezeichnet werden. Dieses Buch erschien erstmals am 21. Oktober 1994 und wurde im März 2012 in einer Auflage von 40 Exemplaren gedruckt.
Designmuster können in drei Hauptkategorien unterteilt werden, und jede Kategorie enthält eine Reihe spezifischer Muster.
Mehrere Muster, die leicht verwechselt werden können: einfache Fabrik S / abstrakte Fabrik A / Fabrikmethode F / Vorlagenmethode T
Die mit dem Wort „Fabrik“: sind nur daran gewöhnt Erstellen Sie Instanzen wie S/A/F; ohne Einschränkung, wie z. B. T; unabhängig, wie z. B. F/T; ohne dass zusätzliche Client-Aufrufe erforderlich sind, wie z. B. S/A.
2.1 Erstellungsmuster
Stellen Sie sicher, dass eine Klasse nur eine Instanz hat und stellen Sie einen globalen Zugriffspunkt bereit.
Es ist zu beachten, dass die Verwendung eines Singletons unter mehreren Klassenladern zu einer Singleton-Instanz unter jedem Ladertyp führt, da jeder Klassenlader seinen eigenen unabhängigen Namespace hat.
Im Folgenden werden vier threadsichere Java-Implementierungsmethoden zusammengefasst. Jede Implementierung kann mit
aufgerufen werden. Runtime.getRuntime()
NumberFormat.getInstance()
2.1.1.1 The Hungry WaySingleton.getInstance().method();
Schlüsselidee: Als statische globale Variable der Klasse wird sie beim Laden der Klasse instanziiert.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } // 基于 classLoader 机制,自动达到了线程安全的效果 public static Singleton getInstance() { return instance; } public void method() { System.out.println("method() OK."); } }
2.1.1.2 Der faule Weg
Schlüsselidee: Synchronisierung auf der Methode getInstance() erreichen.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private static Singleton instance = null; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } public void method() { System.out.println("method() OK."); } }
Schlüsselidee: Überprüfen Sie, ob es nicht erstellt wurde, wenn es nicht synchronisiert ist, und instanziieren Sie es nur, wenn es synchron überprüft wird wurde nicht instanziiert. Um Synchronisationssituationen stark zu reduzieren.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private volatile static Singleton instance = null; // 注意 volatile private Singleton() { } public static Singleton getInstance() { if (instance == null) { // 初步检查:尚未实例化 synchronized (Singleton.class) { // 再次同步(对 Singleton.class) if (instance == null) { // 确认尚未实例化 instance = new Singleton(); } } } return instance; } public void method() { System.out.println("method() OK."); } }
Schlüsselidee: Globale statische Mitglieder werden in internen Klassen platziert und nur dann instanziiert, wenn auf die interne Klasse verwiesen wird, um Verzögerungen zu erreichen Der Zweck der Instanziierung. Dies ist eine perfekte Lösung:
Gewährleistet eine verzögerte Instanziierung des Aufrufs von getInstance();
Keine Sperre erforderlich, gute Leistung
ist nicht durch die JDK-Version eingeschränkt.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private static class InstanceHolder { // 延迟加载实例 private static Singleton instance = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return InstanceHolder.instance; } public void method() { System.out.println("method() OK."); } }
2.1.2 Builder (Builder)
StringBuilder sb = new StringBuilder(); sb.append("Hello world!").append(123).append('!'); System.out.println(sb.toString());
2.1.3 Simple Factory ★StringBuilder
ist kein echtes „Entwurfsmuster“. . Es handelt sich selbst um eine Factory-Implementierungsklasse, die direkt Erstellungsmethoden bereitstellt (es können mehrere sein), bei denen es sich um statische Methoden handeln kann. Es gibt
/** * @author: kefeng.wang * @date: 2016-06-09 19:42 **/public class DPC3_SimpleFactoryPattern { private static class SimpleFactory { public CommonProduct createProduct(int type) { // 工厂方法,返回“产品”接口,形参可无 if (type == 1) { return new CommonProductImplA(); // 产品具体类 } else if (type == 2) { return new CommonProductImplB(); } else if (type == 3) { return new CommonProductImplC(); } else { return null; } } } private static class SimpleFactoryClient { private SimpleFactory factory = null; public SimpleFactoryClient(SimpleFactory factory) { this.factory = factory; } public final void run() { CommonProduct commonProduct1 = factory.createProduct(1); CommonProduct commonProduct2 = factory.createProduct(2); CommonProduct commonProduct3 = factory.createProduct(3); System.out.println(commonProduct1 + ", " + commonProduct2 + ", " + commonProduct3); } } public static void main(String[] args) { SimpleFactory factory = new SimpleFactory(); // 工厂实例 new SimpleFactoryClient(factory).run(); // 传入客户类 } }
2.1.4 Abstrakte Fabrik ★Boolean.valueOf(String)
Class.forName(String)
Eine abstrakte Klasse, die abstrakte Methoden zum Erstellen von Objekten definiert. Implementieren Sie Methoden zum Erstellen von Objekten in mehreren geerbten Implementierungsklassen.
2.1.5 Factory-Methode ★NumberFormat.getInstance()
Die Arbeitsteilung zwischen abstrakten Klassen und Implementierungsklassen beim Erstellen von Methoden ähnelt der „abstrakten Fabrik“.
Wenn der Prozess der Erstellung einer Instanz komplex oder teuer ist, kann dies durch Klonen erreicht werden. Zum Beispiel Javas
Wird für Kombinationsbeziehungen von Klassen oder Objekten verwendet.
Durch die Anpassung einer Schnittstelle an eine andere gewünschte Schnittstelle können Kompatibilitätsprobleme beseitigt werden, die durch Schnittstellenkonflikte verursacht werden.
Passen Sie beispielsweise Enumeration<E>
an Iterator<E>
an, und Arrays.asList()
passen Sie T[]
an List<T>
an.
Dinge bestehen aus mehreren Faktoren, und jeder Faktor hat eine abstrakte Klasse und mehrere Implementierungsklassen. Am Ende können diese mehreren Faktoren frei kombiniert werden.
Zum Beispiel eine Vielzahl von Fernbedienungen + eine Vielzahl von Fernsehern, eine Vielzahl von Automodellen + eine Vielzahl von Straßenbedingungen + eine Vielzahl von Fahrern. JDBC
und AWT
im JDK.
Organisieren Sie den „Teil/das Ganze“ des Objekts in einer Baumstruktur, sodass ein einzelnes Objekt oder eine Kombination mehrerer Objekte einheitlich behandelt werden kann.
Zum Beispiel mehrstufige Menüs, Binärbäume usw.
Verknüpfen Sie Dekoratoren zur Laufzeit dynamisch mit Verantwortlichkeiten.
Es gibt zwei Möglichkeiten, Funktionen zu erweitern. Die Klassenvererbung wird statisch zur Kompilierungszeit bestimmt, während der Dekoratormodus dynamisch zur Laufzeit bestimmt wird, was einzigartige Vorteile bietet.
Nachdem beispielsweise StringReader
mit LineNumberReader
dekoriert wurde, werden line
-bezogene Schnittstellen für den Zeichenstrom erweitert.
bietet eine einheitliche High-Level-Schnittstelle für den Zugriff auf eine Gruppe von Schnittstellen im Subsystem, wodurch das Subsystem einfacher zu verwenden ist.
Um beispielsweise einen Computer zu starten (oder herunterzufahren), ruft er die entsprechenden Start- (oder Herunterfahr-)Schnittstellen der CPU/des Speichers/der Festplatte auf.
Verwenden Sie die Sharing-Technologie, um eine große Anzahl feinkörniger Objekte effektiv zu unterstützen.
Ein Textprozessor muss beispielsweise nicht mehrere Glyphenobjekte für mehrere Vorkommen jedes Zeichens generieren. Stattdessen teilen sich mehrere Vorkommen desselben Zeichens in einer externen Datenstruktur ein einziges Glyphenobjekt. Integer.valueOf(int)
im JDK übernimmt diesen Modus.
Proxy erstellt und speichert einen Verweis auf den Betreff. Wenn der Client den Proxy aufruft, leitet der Proxy ihn an den Betreff weiter.
Zum Beispiel Collections
Sammlungsansicht, RMI/RPC-Fernaufruf, Cache-Proxy, Firewall-Proxy usw. in Java.
wird für die Aufrufbeziehung von Klassen oder Objekten verwendet.
Eine Anfrage wird entlang einer Kette weitergeleitet, bis ein Prozessor in der Kette sie bearbeitet.
Zum Beispiel Filter in SpringMVC.
Kapseln Sie den Befehl als Objekt, das gespeichert/geladen, übertragen, ausgeführt/rückgängig gemacht, in die Warteschlange gestellt, protokolliert usw. werden kann, und den „Anforderer“. der Handlung“ Entkopplung vom „Ausführenden der Handlung“.
Zu den Teilnehmern gehören Invoker (Anrufer) => Befehl (Befehl) => Empfänger (Ausführer).
Zum Beispiel geplante Aufgaben und Thread-Aufgaben Runnable
.
wird verwendet, um einen einfachen Sprachinterpreter zu erstellen, der Skriptsprachen und Programmiersprachen verarbeiten kann, wobei für jede Regel eine Klasse erstellt wird.
Zum Beispiel java.util.Pattern
, java.text.Format
im JDK.
Bietet eine Methode für den sequentiellen Zugriff auf die einzelnen Elemente in einem Aggregatobjekt, ohne dessen interne Darstellung offenzulegen.
Wie java.util.Iterator
und java.util.Enumeration
im JDK.
Verwenden Sie ein vermittelndes Objekt, um eine Reihe von Objektinteraktionen zu kapseln. Das vermittelnde Objekt macht es überflüssig, dass Objekte explizit aufeinander verweisen, wodurch ihre Kopplung und Interaktion zwischen ihnen gelockert wird Sie können unabhängig voneinander geändert werden.
Wie java.util.Timer
und java.util.concurrent.ExecutorService.submit()
im JDK.
Das Memento-Objekt wird zum Speichern einer Momentaufnahme des internen Zustands eines anderen Objekts verwendet und kann extern gespeichert und später in den ursprünglichen Zustand zurückversetzt werden. Wie zum Beispiel die Java-Serialisierung.
Wie java.util.Date
und java.io.Serializable
im JDK.
Eins-zu-viele-Abhängigkeit zwischen Objekten Wenn sich der Status des beobachteten Objekts ändert, wird der Beobachter benachrichtigt.
Zu den Teilnehmern gehört Observable/Observer.
Zum Beispiel Ereignisse in RMI, java.util.EventListener
.
Wenn sich der interne Zustand eines Objekts ändert, ändert sich auch sein Verhalten. Seine interne Implementierung besteht darin, eine übergeordnete Zustandsklasse zu definieren und die Zustandsunterklasse für jeden Zustand zu erweitern. Wenn sich der interne Zustand des Objekts ändert, wechselt auch die ausgewählte Zustandsunterklasse, die Außenseite muss jedoch nur mit dem Objekt interagieren und weiß es nicht Existenz von Zustandsunterklassen.
Zum Beispiel der Stopp-/Wiedergabe-/Pause-Status des Videoplayers.
Definieren Sie eine Reihe von Algorithmen, die separat gekapselt und kundenunabhängig sind. Wenn der Algorithmus geändert wird, hat dies keine Auswirkungen auf die Kundennutzung.
Zum Beispiel können verschiedene Charaktere im Spiel unterschiedliche Ausrüstung verwenden und diese Ausrüstung kann auf strategische Weise verpackt werden.
Wie zum Beispiel java.util.Comparator#compare()
im JDK.
Die abstrakte Klasse definiert das logische Framework der obersten Ebene (genannt „Vorlagenmethode“), und einige Schritte (können Instanzen oder andere Vorgänge erstellen) werden verzögert Zur Unterklassenimplementierung kann es unabhängig betrieben werden.
Wenn die von der Unterklasse implementierte Operation darin besteht, eine Instanz zu erstellen, wird die Vorlagenmethode zum Fabrikmethodenmuster, sodass die Fabrikmethode eine spezielle Vorlagenmethode ist.
Ohne die Datenstruktur des Besuchers zu ändern, kapselt der Besucher den Zugriffsvorgang. Der entscheidende Punkt ist, dass der Besucher die aufgerufene Schnittstelle bereitstellt.
Das anwendbare Szenario ist, dass die Besucher stabil, aber flexibel sind oder dass die Besucher viele verschiedene Arten von Vorgängen haben.
Kombinieren Sie zwei oder mehr Modi, um eine Lösung für häufig auftretende Probleme zu finden.
Anwendungsfall: MVC-Muster (Modell/Ansicht/Controller) unter Verwendung von Observer, Strategy, Composite, Factory, Decorator und anderen Mustern.
Anwendungsfall: Haushaltsgeräte = Schnittstelle + Daten + Logiksteuerung, Einkaufszentrum = Geschäft + Lager + Logiksteuerung.
Wikipedia: Entwurfsmuster
Wikipedia: Software-Entwurfsmuster
TutorialsPoint: Entwurfsmuster
Entwurfsmuster sind spezifische Situationen, die ständig auftreten. spezifische Lösungsmuster (Routinen), die für bestimmte Probleme immer wieder verwendet werden können. Dieser Artikel fasst die wichtigsten Punkte der Verwendung von 24 gängigen Entwurfsmustern gemäß den drei Kategorien Erstellung, Struktur und Verhalten zusammen, einschließlich anwendbarer Szenarien, Lösungen und ihrer entsprechenden Java-Implementierungen.
Verwandte Artikel:
Detaillierte Erläuterung gängiger Java-Designmuster – Factory-Muster
Das obige ist der detaillierte Inhalt vonFassen Sie die Hauptanwendungspunkte von 24 gängigen Entwurfsmustern und ihrer Java-Implementierung zusammen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!