Wenn es darum geht, sauberen, wartbaren und effizienten Code zu schreiben, spielen Entwurfsmuster in der Welt der Softwareentwicklung eine entscheidende Rolle. Entwurfsmuster sind wiederverwendbare Lösungen für häufige Probleme, mit denen Entwickler beim Entwerfen und Erstellen von Softwaresystemen konfrontiert sind. Sie bieten einen strukturierten Ansatz zur Lösung spezifischer Herausforderungen und erleichtern so die Erstellung von Code, der nicht nur robust, sondern auch einfacher zu verstehen und zu warten ist.
Bei der objektorientierten Programmierung (OOP ) dienen Entwurfsmuster als Richtlinien für die Strukturierung Ihres Codes auf eine Weise, die Flexibilität, Wiederverwendbarkeit und Skalierbarkeit fördert. Sie fassen Best Practices und Designprinzipien zusammen, die weiterentwickelt und in bewährte Lösungen umgesetzt wurden.
Entwurfsmuster können in drei Hauptgruppen eingeteilt werden:
Erstellungsmuster: Diese Muster konzentrieren sich auf Objekterstellungsmechanismen und versuchen, Objekte auf eine für die Situation geeignete Weise zu erstellen. Sie abstrahieren den Instanziierungsprozess und machen ihn dadurch flexibler und unabhängiger vom System.
Strukturmuster: Strukturmuster befassen sich mit der Objektzusammensetzung und bilden Beziehungen zwischen Objekten, um größere, komplexere Strukturen zu schaffen. Sie helfen zu definieren, wie Objekte und Klassen kombiniert werden können, um neue Strukturen zu bilden und neue Funktionalität bereitzustellen.
Verhaltensmuster: Verhaltensmuster befassen sich mit der Kommunikation zwischen Objekten und definieren, wie sie interagieren und Verantwortlichkeiten verteilen. Mithilfe dieser Muster können Sie Systeme entwerfen, in denen Objekte flexibler und effizienter zusammenarbeiten.
Hier ist eine Liste einiger gängiger Designmuster in jeder Kategorie:
Beobachtermuster: Definiert eine Eins-zu-viele-Abhängigkeit zwischen Objekten. Wenn also ein Objekt seinen Status ändert, werden alle seine Abhängigkeiten automatisch benachrichtigt und aktualisiert.
Strategiemuster: Definiert eine Familie von Algorithmen, kapselt jeden einzelnen und macht sie austauschbar.
Befehlsmuster: Kapselt eine Anfrage als Objekt und ermöglicht so die Parametrisierung von Clients mit Warteschlangen, Anfragen und Vorgängen.
Zustandsmuster: Ermöglicht einem Objekt, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert, indem es das Verhalten in separate Klassen einschließt.
Muster der Verantwortungskette: Leitet die Anfrage entlang einer Kette von Handlern weiter, sodass jeder Handler entscheiden kann, ob er die Anfrage verarbeiten oder an den nächsten Handler in der Kette weiterleiten möchte.
Besuchermuster: Dies stellt eine Operation dar, die an den Elementen einer Objektstruktur ausgeführt werden soll, sodass Sie neue Operationen definieren können, ohne die Klassen der Elemente zu ändern.
In diesem Blog werden wir uns mit jedem dieser Entwurfsmuster befassen und Erklärungen, reale Anwendungsfälle und JavaScript- Codebeispiele bereitstellen, damit Sie sie verstehen und effektiv in Ihren Projekten implementieren können.
Das Singleton-Muster ist ein kreatives Entwurfsmuster, das sicherstellt, dass eine Klasse nur eine Instanz hat, und einen globalen Zugriffspunkt auf diese Instanz bereitstellt. Dieses Muster ist besonders nützlich, wenn Sie die Anzahl der Instanzen einer Klasse in Ihrer Anwendung begrenzen und den Zugriff auf eine einzelne gemeinsam genutzte Instanz steuern möchten.
In JavaScript ist die Implementierung des Singleton-Musters dank der Flexibilität der Sprache relativ einfach. Schauen wir uns ein einfaches Beispiel für die Erstellung eines Singletons in JavaScript an.
// Singleton instance let instance = null;
class Singleton { constructor() { if (!instance) { instance = this; // Your initialization code here } else { return instance; } } // Your methods and properties here }// Usage const singletonA = new Singleton(); const singletonB = new Singleton(); console.log(singletonA === singletonB); // Output: true (both variables reference the same instance)
In diesem Beispiel erstellen wir eine Singleton-Klasse mit einem Konstruktor, der prüft, ob bereits eine Instanz vorhanden ist. Wenn keine Instanz vorhanden ist, wird eine erstellt und der Instanzvariablen zugewiesen. Nachfolgende Aufrufe des Konstruktors geben die vorhandene Instanz zurück und stellen so sicher, dass es nur eine Instanz der Singleton-Klasse gibt.
Das Singleton-Muster ist in verschiedenen Szenarien nützlich, darunter:
Obwohl das Singleton-Muster von Vorteil sein kann, ist es wichtig, es mit Bedacht einzusetzen. Eine übermäßige Verwendung des Singleton-Musters kann zu einer engen Kopplung von Code und globalem Status führen, was die Wartung und das Testen Ihrer Anwendung erschweren kann. Daher ist es wichtig, die Vor- und Nachteile abzuwägen und das Muster dort anzuwenden, wo es Ihrer Codebasis wirklich einen Mehrwert verleiht.
Das Factory Pattern und das Abstract Factory Pattern sind kreative Designmuster, die sich mit der Erstellung von Objekten befassen, dies jedoch auf unterschiedliche Weise und mit unterschiedlichen Zwecken. Lassen Sie uns jedes dieser Muster untersuchen und sehen, wie sie in JavaScript implementiert werden können.
Das Factory-Muster ist ein Erstellungsmuster, das eine Schnittstelle zum Erstellen von Objekten bereitstellt, es Unterklassen jedoch ermöglicht, den Typ der zu erstellenden Objekte zu ändern. Es kapselt den Objekterstellungsprozess, wodurch er flexibler und vom Client-Code entkoppelt wird.
// Product class class Product { constructor(name) { this.name = name; } }
// Factory for creating products class ProductFactory { createProduct(name) { return new Product(name); } }// Usage const factory = new ProductFactory(); const productA = factory.createProduct('Product A'); const productB = factory.createProduct('Product B');console.log(productA.name); // Output: 'Product A' console.log(productB.name); // Output: 'Product B'
In diesem Beispiel ist die ProductFactory für die Erstellung von Instanzen der Product-Klasse verantwortlich. Es abstrahiert den Erstellungsprozess und ermöglicht Ihnen die Erstellung verschiedener Produkttypen durch Erweiterung der Fabrik.
Das Abstract Factory Pattern ist ein weiteres Erstellungsmuster, das eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte bereitstellt, ohne deren konkrete Klassen anzugeben. Damit können Sie Gruppen von Objekten erstellen, die harmonisch zusammenarbeiten.
// Abstract Product classes class Button { render() {} }
class Checkbox { render() {} }// Concrete Product classes class MacButton extends Button { render() { return 'Render Mac button'; } }class MacCheckbox extends Checkbox { render() { return 'Render Mac checkbox'; } }class WindowsButton extends Button { render() { return 'Render Windows button'; } }class WindowsCheckbox extends Checkbox { render() { return 'Render Windows checkbox'; } }// Abstract Factory interface class GUIFactory { createButton() {} createCheckbox() {} }// Concrete Factories class MacFactory extends GUIFactory { createButton() { return new MacButton(); } createCheckbox() { return new MacCheckbox(); } }class WindowsFactory extends GUIFactory { createButton() { return new WindowsButton(); } createCheckbox() { return new WindowsCheckbox(); } }// Usage function createUI(factory) { const button = factory.createButton(); const checkbox = factory.createCheckbox(); return { button, checkbox }; }const macUI = createUI(new MacFactory()); console.log(macUI.button.render()); // Output: 'Render Mac button' console.log(macUI.checkbox.render()); // Output: 'Render Mac checkbox'const windowsUI = createUI(new WindowsFactory()); console.log(windowsUI.button.render()); // Output: 'Render Windows button' console.log(windowsUI.checkbox.render()); // Output: 'Render Windows checkbox'
In diesem Beispiel haben wir zwei konkrete Fabriken, MacFactory und WindowsFactory, die jeweils in der Lage sind, eine Reihe verwandter UI-Komponenten (Schaltflächen und Kontrollkästchen) für ihre jeweiligen Plattformen zu erstellen. Mit der Funktion „createUI“ können Sie mithilfe der entsprechenden Factory eine zusammenhängende Benutzeroberfläche für eine bestimmte Plattform erstellen.
Wann welches Muster verwendet werden sollte:
Das Builder-Muster ist ein kreatives Entwurfsmuster, das die Konstruktion eines komplexen Objekts von seiner Darstellung trennt und es ermöglicht, mit demselben Konstruktionsprozess unterschiedliche Darstellungen zu erstellen. Dieses Muster ist besonders nützlich, wenn Sie ein Objekt mit einer großen Anzahl von Eigenschaften haben und die Erstellung von Instanzen vereinfachen und gleichzeitig die Flexibilität beibehalten möchten.
In JavaScript wird das Builder-Muster häufig mithilfe einer Builder-Klasse oder eines Builder-Objekts implementiert, das den schrittweisen Aufbau des komplexen Objekts leitet. Schauen wir uns ein Beispiel an, um zu verstehen, wie es funktioniert.
// Product class with multiple properties class Product { constructor() { this.name = ''; this.price = 0; this.color = 'white'; // ... other properties }
// Additional methods can be defined here }// Builder for creating Product instances class ProductBuilder { constructor() { this.product = new Product(); } setName(name) { this.product.name = name; return this; // Return the builder for method chaining } setPrice(price) { this.product.price = price; return this; } setColor(color) { this.product.color = color; return this; } // Other methods to set additional properties build() { return this.product; // Return the fully constructed product } }// Usage const builder = new ProductBuilder();const productA = builder .setName('Product A') .setPrice(99.99) .setColor('blue') .build();const productB = builder .setName('Product B') .setPrice(49.99) .build();console.log(productA); console.log(productB);
In diesem Beispiel haben wir eine Produktklasse mit mehreren Eigenschaften. Die ProductBuilder-Klasse hilft beim Erstellen von Produktinstanzen, indem sie Methoden bereitstellt, um jede Eigenschaft Schritt für Schritt festzulegen. Durch die Methodenverkettung können Sie mehrere Eigenschaften auf flüssige und lesbare Weise festlegen. Schließlich gibt die Build-Methode die vollständig erstellte Produktinstanz zurück.
Das Builder-Muster ist in verschiedenen Szenarien von Vorteil, darunter:
Obwohl das Builder-Muster viele Vorteile bietet, ist es wichtig zu beachten, dass es Ihre Codebasis komplexer macht, insbesondere wenn die zu erstellenden Objekte relativ einfach sind. Daher ist es wichtig zu bewerten, ob die durch den Builder eingeführte Komplexität für Ihren spezifischen Anwendungsfall gerechtfertigt ist.
Das Prototype-Muster ist ein kreatives Designmuster, mit dem Sie neue Objekte erstellen können, indem Sie ein vorhandenes Objekt kopieren, das als Prototyp bezeichnet wird. Es fördert die Erstellung von Objekten, ohne die genaue Klasse des zu erstellenden Objekts anzugeben. Dieses Muster ist besonders nützlich, wenn Sie effizient Instanzen komplexer Objekte erstellen möchten.
In JavaScript ist das Prototypmuster eng mit der integrierten prototype
und der Methode Object.create()
verknüpft. Lassen Sie uns untersuchen, wie Sie das Prototypmuster in JavaScript implementieren und verwenden.
// Prototype object const vehiclePrototype = { init(make, model) { this.make = make; this.model = model; }, getDetails() { return `${this.make} ${this.model}`; }, };
// Create new instances using the prototype const car1 = Object.create(vehiclePrototype); car1.init('Toyota', 'Camry');const car2 = Object.create(vehiclePrototype); car2.init('Honda', 'Civic');console.log(car1.getDetails()); // Output: 'Toyota Camry' console.log(car2.getDetails()); // Output: 'Honda Civic'
In diesem Beispiel definieren wir ein vehiclePrototype
Objekt mit Methoden und Eigenschaften, die allen Fahrzeugen gemeinsam sind. Wir verwenden Object.create()
, um basierend auf diesem Prototyp neue Instanzen (car1 und car2) zu erstellen. Diese Instanzen erben die Eigenschaften und Methoden des Prototyps, sodass Sie effizient neue Objekte mit gemeinsamem Verhalten erstellen können.
Das Prototypmuster ist in verschiedenen Szenarien wertvoll, darunter:
Obwohl das Prototypmuster nützlich ist, gibt es einige Überlegungen:
Das Object Pool Pattern ist ein kreatives Designmuster, das einen Pool wiederverwendbarer Objekte verwaltet, um den Aufwand für die Objekterstellung und -zerstörung zu minimieren. Dies ist besonders nützlich, wenn das Erstellen und Zerstören von Objekten teuer oder ressourcenintensiv ist. Das Object Pool Pattern trägt zur Verbesserung der Leistung und Ressourcennutzung bei, indem es Objekte recycelt und wiederverwendet, anstatt von Grund auf neue zu erstellen.
In JavaScript können Sie das Object Pool Pattern mithilfe von Arrays oder benutzerdefinierten Poolverwaltungsklassen implementieren. Lassen Sie uns anhand eines einfachen Beispiels untersuchen, wie dieses Muster funktioniert.
class ObjectPool { constructor(maxSize) { this.maxSize = maxSize; this.pool = []; }
create() { if (this.pool.length < this.maxSize) { // Create a new object and add it to the pool const obj = { /* Your object initialization code here */ }; this.pool.push(obj); return obj; } else { // Pool is full, cannot create more objects console.log('Pool is full. Cannot create more objects.'); return null; } } reuse() { if (this.pool.length > 0) { // Reuse an object from the pool return this.pool.pop(); } else { // Pool is empty, no objects available for reuse console.log('Pool is empty. No objects available for reuse.'); return null; } } release(obj) { // Release an object back to the pool for reuse this.pool.push(obj); } }// Usage const pool = new ObjectPool(5); // Create a pool with a maximum size of 5 objectsconst obj1 = pool.create(); const obj2 = pool.create(); const obj3 = pool.create();pool.release(obj2); // Release obj2 back to the pool for reuseconst obj4 = pool.reuse(); // Reuse an object from the pool (obj2)
In diesem Beispiel erstellen wir eine ObjectPool-Klasse, die einen Pool von Objekten verwaltet. Die Methode „create“ erstellt neue Objekte, wenn der Pool nicht voll ist, die Methode „reuse“ ruft ein Objekt aus dem Pool zur Wiederverwendung ab und die Methode „release“ gibt ein Objekt zur zukünftigen Verwendung an den Pool zurück.
Das Objektpoolmuster ist in verschiedenen Szenarios nützlich, darunter:
Obwohl das Objektpoolmuster Leistungsvorteile bietet, ist es wichtig, Folgendes zu berücksichtigen:
Das Adaptermuster ist ein strukturelles Entwurfsmuster, das die Zusammenarbeit von Objekten mit inkompatiblen Schnittstellen ermöglicht. Es fungiert als Brücke zwischen zwei inkompatiblen Schnittstellen und macht sie kompatibel, ohne ihren Quellcode zu ändern. Dieses Muster ist besonders nützlich, wenn Sie vorhandenen Code integrieren oder verwenden müssen, der nicht ganz zu den Anforderungen Ihrer Anwendung passt.
In JavaScript kann das Adaptermuster mithilfe von Klassen oder Funktionen implementiert werden, die die inkompatible Schnittstelle umschließen oder anpassen. Lassen Sie uns anhand eines praktischen Beispiels untersuchen, wie das Adaptermuster in JavaScript implementiert und verwendet wird.
Angenommen, Sie haben eine vorhandene Klasse namens OldSystem
mit einer Methode namens legacyRequest
:
class OldSystem { legacyRequest() { return 'Data from the legacy system'; } }
Nun möchten Sie dieses Legacy-System in Ihrer modernen Anwendung verwenden, die eine andere Schnittstelle erwartet. Sie können eine Adapterklasse oder -funktion wie folgt erstellen:
class Adapter { constructor(oldSystem) { this.oldSystem = oldSystem; }
newRequest() { const legacyData = this.oldSystem.legacyRequest(); // Adapt the data or perform any necessary transformations return `Adapted: ${legacyData}`; } }
Jetzt können Sie die Adapter-Klasse verwenden, um das Legacy-System mit Ihrer modernen Anwendung kompatibel zu machen:
const oldSystem = new OldSystem(); const adapter = new Adapter(oldSystem);
const result = adapter.newRequest(); console.log(result); // Output: 'Adapted: Data from the legacy system'
In diesem Beispiel umschließt die Adapter-Klasse das OldSystem und stellt eine neue Schnittstelle, newRequest, bereit, die mit Ihrer modernen Anwendung kompatibel ist.
Das Adaptermuster ist in verschiedenen Szenarios wertvoll, darunter:
Obwohl das Adaptermuster Flexibilität und Kompatibilität bietet, ist es wichtig, einige Punkte zu berücksichtigen:
Das Decorator-Muster ist ein strukturelles Entwurfsmuster, mit dem Sie Objekten dynamisch neue Verhaltensweisen oder Verantwortlichkeiten hinzufügen können, ohne deren vorhandenen Code zu ändern. Es ist eine leistungsstarke Möglichkeit, die Funktionalität von Objekten zu erweitern, indem sie mit Dekorationsobjekten umhüllt werden. Dieses Muster fördert das Prinzip „Offen für Erweiterungen, aber geschlossen für Änderungen“ und macht es einfach, Objekten neue Funktionen hinzuzufügen, ohne ihre Kernimplementierung zu ändern.
In JavaScript kann das Decorator-Muster mithilfe von Klassen und Objektzusammensetzung implementiert werden. Lassen Sie uns anhand eines praktischen Beispiels untersuchen, wie das Decorator-Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie haben eine Basisklasse Coffee
:
class Coffee { cost() { return 5; // Base cost of a regular coffee } } Now, you want to add decorators to your coffee to customize it with additional options, such as milk and sugar:
javascript Copy code class MilkDecorator { constructor(coffee) { this.coffee = coffee; } cost() { return this.coffee.cost() + 2; // Adding the cost of milk } }class SugarDecorator { constructor(coffee) { this.coffee = coffee; } cost() { return this.coffee.cost() + 1; // Adding the cost of sugar } }
Anschließend können Sie dekorierte Kaffeeinstanzen wie folgt erstellen:
const regularCoffee = new Coffee(); const coffeeWithMilk = new MilkDecorator(regularCoffee); const coffeeWithMilkAndSugar = new SugarDecorator(coffeeWithMilk);
console.log(regularCoffee.cost()); // Output: 5 console.log(coffeeWithMilk.cost()); // Output: 7 console.log(coffeeWithMilkAndSugar.cost()); // Output: 8
In diesem Beispiel haben wir die Coffee-Klasse, die einen Basiskaffee darstellt. Die Klassen MilkDecorator und SugarDecorator sind Dekoratoren, die ein Kaffeeobjekt einpacken und die Kosten für Milch bzw. Zucker zu den Grundkosten hinzufügen.
Das Dekoratormuster ist in verschiedenen Szenarien wertvoll, darunter:
Obwohl das Decorator-Muster vielseitig einsetzbar ist, ist es wichtig, einige Überlegungen zu beachten:
Das Proxy-Muster ist ein strukturelles Entwurfsmuster, das einen Ersatz oder Platzhalter für ein anderes Objekt bereitstellt, um den Zugriff darauf zu steuern. Es fungiert als Vermittler oder Wrapper für das Zielobjekt und ermöglicht es Ihnen, zusätzliche Verhaltensweisen hinzuzufügen, den Zugriff zu steuern oder die Objekterstellung zu verzögern. Das Proxy-Muster ist in verschiedenen Szenarien nützlich, z. B. bei der Implementierung von Lazy Loading, Zugriffskontrolle und Protokollierung.
In JavaScript können Proxys mithilfe des integrierten Proxy
Objekts erstellt werden. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Proxy-Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie haben ein ressourcenintensives Objekt, das Sie nur dann langsam laden möchten, wenn es benötigt wird. Sie können einen Proxy verwenden, um verzögertes Laden zu erreichen:
class ExpensiveResource { constructor() { console.log('Creating an expensive resource...'); }
fetchData() { console.log('Fetching data...'); } }class LazyResourceProxy { constructor() { this.resource = null; } fetchData() { if (!this.resource) { this.resource = new ExpensiveResource(); } this.resource.fetchData(); } }// Usage const lazyResource = new LazyResourceProxy(); // The actual resource is created and data is fetched only when needed lazyResource.fetchData();
In diesem Beispiel fungiert LazyResourceProxy als Ersatz für ExpensiveResource und erstellt die eigentliche Ressource nur, wenn die fetchData-Methode zum ersten Mal aufgerufen wird.
Sie können Proxys auch verwenden, um den Zugriff auf Objekte und deren Eigenschaften zu steuern:
const user = { username: 'john_doe', password: 'secret123', };
const userProxy = new Proxy(user, { get(target, property) { if (property === 'password') { throw new Error('Access denied to password.'); } return target[property]; }, });console.log(userProxy.username); // Output: 'john_doe' console.log(userProxy.password); // Throws an error: 'Access denied to password.'
In diesem Beispiel fängt der Proxy den Get-Vorgang ab und schränkt den Zugriff auf die Passworteigenschaft ein.
Das Proxy-Muster ist in verschiedenen Szenarien wertvoll, darunter:
Beachten Sie bei der Verwendung des Proxy-Musters die folgenden Überlegungen:
Das zusammengesetzte Muster ist ein strukturelles Entwurfsmuster, mit dem Sie Objekte zu baumartigen Strukturen zusammensetzen können, um Teil-Ganze-Hierarchien darzustellen. Dadurch können Kunden einzelne Objekte und Objektkompositionen einheitlich behandeln. Das zusammengesetzte Muster ist besonders nützlich, wenn Sie mit komplexen Strukturen arbeiten müssen, die aus kleineren, zusammengehörigen Objekten bestehen, und dabei eine konsistente Schnittstelle beibehalten müssen.
In JavaScript können Sie das zusammengesetzte Muster mithilfe von Klassen oder Objekten implementieren, die eine gemeinsame Schnittstelle haben, und so hierarchische Strukturen erstellen. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das zusammengesetzte Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie erstellen eine Grafikdesignanwendung, die sowohl mit einfachen Formen als auch mit komplexen Formenzusammensetzungen (z. B. Gruppen) arbeiten muss. Sie können das zusammengesetzte Muster verwenden, um diese Hierarchie darzustellen:
// Component interface class Graphic { draw() {} }
// Leaf class (represents simple shapes) class Circle extends Graphic { constructor() { super(); // Circle-specific properties and methods } draw() { // Draw a circle } }// Composite class (represents groups of shapes) class Group extends Graphic { constructor() { super(); this.graphics = []; } add(graphic) { this.graphics.push(graphic); } draw() { // Draw each graphic in the group this.graphics.forEach((graphic) => graphic.draw()); } }// Usage const circle1 = new Circle(); const circle2 = new Circle(); const group = new Group();group.add(circle1); group.add(circle2);group.draw(); // Draws both circles in the group
In diesem Beispiel dient die Graphic-Klasse als Komponentenschnittstelle. Die Circle-Klasse stellt einfache Formen dar, während die Group-Klasse Kompositionen aus Formen darstellt. Sowohl die Circle- als auch die Group-Klasse implementieren die Draw-Methode, sodass Sie sie beim Rendern einheitlich behandeln können.
Das zusammengesetzte Muster ist in verschiedenen Szenarien wertvoll, darunter:
Berücksichtigen Sie beim Arbeiten mit dem zusammengesetzten Muster Folgendes:
Das Brückenmuster ist ein strukturelles Entwurfsmuster, das die Abstraktion eines Objekts von seiner Implementierung trennt. Dadurch können Sie eine Brücke zwischen den beiden schlagen und sie unabhängig voneinander variieren lassen. Dieses Muster ist besonders nützlich, wenn Sie eine dauerhafte Bindung zwischen einer Abstraktion und ihrer Implementierung vermeiden möchten, um Ihren Code flexibler und wartbarer zu machen.
In JavaScript kann das Bridge Pattern mithilfe von Klassen und Objekten implementiert werden, die eine abstrakte Schnittstelle für die Abstraktion und verschiedene konkrete Implementierungen für verschiedene Plattformen oder Funktionen bereitstellen. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Bridge-Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie erstellen eine Zeichenanwendung, die Formen auf verschiedenen Plattformen wie Webbrowsern und Mobilgeräten rendern kann. Sie können das Brückenmuster verwenden, um die Zeichnungsformen (Abstraktion) von der Rendering-Logik (Implementierung) zu trennen:
// Abstraction class Shape { constructor(renderer) { this.renderer = renderer; }
draw() { // Delegating the drawing to the specific renderer this.renderer.renderShape(this); } }// Implementor interface class Renderer { renderShape(shape) {} }// Concrete Implementors class WebRenderer extends Renderer { renderShape(shape) { console.log(`Drawing on the web: ${shape.constructor.name}`); } }class MobileRenderer extends Renderer { renderShape(shape) { console.log(`Drawing on mobile: ${shape.constructor.name}`); } }// Concrete Abstractions (Shapes) class Circle extends Shape { constructor(renderer) { super(renderer); } }class Square extends Shape { constructor(renderer) { super(renderer); } }// Usage const webRenderer = new WebRenderer(); const mobileRenderer = new MobileRenderer();const circle = new Circle(webRenderer); const square = new Square(mobileRenderer);circle.draw(); // Output: Drawing on the web: Circle square.draw(); // Output: Drawing on mobile: Square
In diesem Beispiel repräsentiert die Shape-Klasse die Abstraktion (zu zeichnende Formen) und die Renderer-Klasse repräsentiert die Implementor-Schnittstelle (plattformspezifische Rendering-Logik). Verschiedene konkrete Implementierer (WebRenderer und MobileRenderer) stellen Rendering-Logik für Web- bzw. mobile Plattformen bereit. Die Klassen Circle und Square sind konkrete Abstraktionen, die Formen darstellen.
Das Brückenmuster ist in verschiedenen Szenarien wertvoll, darunter:
Beachten Sie bei der Verwendung des Bridge-Musters Folgendes:
Das Flyweight-Muster ist ein strukturelles Entwurfsmuster, das darauf abzielt, den Speicherverbrauch zu reduzieren und die Leistung durch die gemeinsame Nutzung gemeinsamer Teile von Objekten zu verbessern. Dies wird dadurch erreicht, dass der intrinsische Zustand eines Objekts (gemeinsam und unveränderlich) von seinem extrinsischen Zustand (einzigartig und kontextabhängig) getrennt wird. Dieses Muster ist besonders nützlich, wenn Sie über eine große Anzahl ähnlicher Objekte verfügen und den Speicherbedarf minimieren möchten.
In JavaScript können Sie das Flyweight-Muster mithilfe von Klassen oder Objekten implementieren, um einen gemeinsamen intrinsischen Zustand und einen einzelnen extrinsischen Zustand darzustellen. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Flyweight-Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie entwickeln einen Texteditor, der eine große Textmenge anzeigen muss. Anstatt für jedes Zeichen ein separates Objekt zu erstellen, können Sie das Flyweight-Muster verwenden, um Zeichenobjekte gemeinsam zu nutzen, wenn sie dieselben intrinsischen Eigenschaften haben (z. B. Schriftart und -größe):
class Character { constructor(char, font, size) { this.char = char; this.font = font; this.size = size; }
render() { console.log(`Rendering character "${this.char}" in ${this.font}, size ${this.size}`); } }class CharacterFactory { constructor() { this.characters = {}; } getCharacter(char, font, size) { const key = `${char}-${font}-${size}`; if (!this.characters[key]) { this.characters[key] = new Character(char, font, size); } return this.characters[key]; } }// Usage const factory = new CharacterFactory();const charA1 = factory.getCharacter('A', 'Arial', 12); const charA2 = factory.getCharacter('A', 'Arial', 12); const charB = factory.getCharacter('B', 'Times New Roman', 14);charA1.render(); // Output: Rendering character "A" in Arial, size 12 charA2.render(); // Output: Rendering character "A" in Arial, size 12 (shared instance) charB.render(); // Output: Rendering character "B" in Times New Roman, size 14
In diesem Beispiel stellt die Character-Klasse einzelne Zeichen mit intrinsischen Eigenschaften wie dem Zeichen selbst, der Schriftart und der Größe dar. Die CharacterFactory-Klasse stellt sicher, dass Zeichen mit denselben intrinsischen Eigenschaften gemeinsam genutzt und nicht dupliziert werden.
Das Fliegengewichtsmuster ist in verschiedenen Szenarien wertvoll, darunter:
Beachten Sie bei der Verwendung des Fliegengewichtsmusters Folgendes:
Das Beobachtermuster ist ein Verhaltensentwurfsmuster, das eine Eins-zu-Viele-Abhängigkeit zwischen Objekten herstellt. Dadurch kann ein Objekt (das Subjekt oder das Observable) mehrere Beobachter (Listener) über Änderungen seines Zustands oder seiner Daten benachrichtigen. Dieses Muster wird häufig für die Implementierung verteilter Ereignisverarbeitungssysteme verwendet, bei denen Zustandsänderungen eines Objekts Aktionen in anderen abhängigen Objekten auslösen.
In JavaScript können Sie das Observer-Muster mithilfe benutzerdefinierter Klassen oder integrierter Funktionen wie Ereignis-Listener und der Methode addEventListener
implementieren. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Observer-Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie erstellen eine Wetteranwendung und möchten, dass verschiedene Teile der Benutzeroberfläche aktualisiert werden, wenn sich die Wetterbedingungen ändern. Sie können eine benutzerdefinierte Implementierung des Observer-Musters verwenden:
class WeatherStation { constructor() { this.observers = []; }
addObserver(observer) { this.observers.push(observer); } removeObserver(observer) { const index = this.observers.indexOf(observer); if (index !== -1) { this.observers.splice(index, 1); } } notifyObservers() { this.observers.forEach((observer) => { observer.update(this); }); } setWeatherData(weatherData) { this.weatherData = weatherData; this.notifyObservers(); } }class WeatherDisplay { update(weatherStation) { console.log(`Current weather: ${weatherStation.weatherData}`); } }// Usage const weatherStation = new WeatherStation(); const display1 = new WeatherDisplay(); const display2 = new WeatherDisplay();weatherStation.addObserver(display1); weatherStation.addObserver(display2);weatherStation.setWeatherData('Sunny'); // Both displays update with the new weather data
In diesem Beispiel fungiert die Wetterstation als Subjekt, das Beobachter (Anzeigeobjekte) benachrichtigt, wenn sich die Wetterdaten ändern. Beobachter abonnieren das Subjekt mithilfe der Methode addObserver und implementieren die Methode update, um auf Änderungen zu reagieren.
JavaScript bietet außerdem eine integrierte Möglichkeit, das Observer-Muster mithilfe von Ereignis-Listenern zu implementieren:
class NewsPublisher { constructor() { this.subscribers = []; }
subscribe(subscriber) { this.subscribers.push(subscriber); } unsubscribe(subscriber) { const index = this.subscribers.indexOf(subscriber); if (index !== -1) { this.subscribers.splice(index, 1); } } publishNews(news) { this.subscribers.forEach((subscriber) => { subscriber(news); }); } }// Usage const publisher = new NewsPublisher();const subscriber1 = (news) => { console.log(`Subscriber 1 received news: ${news}`); };const subscriber2 = (news) => { console.log(`Subscriber 2 received news: ${news}`); };publisher.subscribe(subscriber1); publisher.subscribe(subscriber2);publisher.publishNews('Breaking News: Important Announcement');
In diesem Beispiel fungiert der NewsPublisher als Betreff und Abonnenten (Funktionen) werden mithilfe der subscribe-Methode hinzugefügt. Die Methode „publishNews“ benachrichtigt Abonnenten, indem sie ihre Funktionen mit den Nachrichten aufruft.
Das Beobachtermuster ist in verschiedenen Szenarien wertvoll, darunter:
Berücksichtigen Sie bei der Verwendung des Observer-Musters Folgendes:
Das Strategiemuster ist ein Verhaltensentwurfsmuster, mit dem Sie eine Familie austauschbarer Algorithmen definieren, jeden einzelnen kapseln und austauschbar machen können. Es ermöglicht Clients, den geeigneten Algorithmus zur Laufzeit dynamisch auszuwählen. Dieses Muster fördert Flexibilität und Wiederverwendbarkeit, indem es das Verhalten des Algorithmus von dem Kontext trennt, der ihn verwendet.
In JavaScript können Sie das Strategiemuster implementieren, indem Sie Objekte oder Funktionen verwenden, um verschiedene Strategien darzustellen, und ein Kontextobjekt, das zwischen diesen Strategien wechseln kann. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Strategiemuster in JavaScript implementiert und verwendet wird.
Angenommen, Sie entwickeln eine E-Commerce-Anwendung und möchten Rabatte für verschiedene Kundentypen berechnen. Sie können das Strategiemuster verwenden, um Rabattstrategien zu kapseln:
// Discount Strategies const regularCustomerDiscount = (amount) => amount * 0.1; // 10% discount const premiumCustomerDiscount = (amount) => amount * 0.2; // 20% discount
// Context class ShoppingCart { constructor(discountStrategy) { this.items = []; this.discountStrategy = discountStrategy; } addItem(item) { this.items.push(item); } calculateTotal() { const subtotal = this.items.reduce((total, item) => total + item.price, 0); return subtotal - this.discountStrategy(subtotal); } }// Usage const regularCustomerCart = new ShoppingCart(regularCustomerDiscount); const premiumCustomerCart = new ShoppingCart(premiumCustomerDiscount);regularCustomerCart.addItem({ name: 'Item 1', price: 50 }); premiumCustomerCart.addItem({ name: 'Item 2', price: 100 });console.log(`Regular Customer Total: $${regularCustomerCart.calculateTotal()}`); // Output: $45 (after 10% discount) console.log(`Premium Customer Total: $${premiumCustomerCart.calculateTotal()}`); // Output: $80 (after 20% discount)
In diesem Beispiel definieren wir zwei Rabattstrategien als Funktionen (regularCustomerDiscount und premiumCustomerDiscount). Die ShoppingCart-Klasse nimmt eine Rabattstrategie als Parameter und berechnet den Gesamtpreis basierend auf der gewählten Strategie.
Das Strategiemuster ist in verschiedenen Szenarien wertvoll, darunter:
Berücksichtigen Sie bei der Verwendung des Strategiemusters Folgendes:
Das Befehlsmuster ist ein Verhaltensentwurfsmuster, das eine Anfrage oder einen einfachen Vorgang in ein eigenständiges Objekt umwandelt. Es ermöglicht Ihnen, Objekte mit unterschiedlichen Anforderungen zu parametrisieren, die Ausführung einer Anforderung zu verzögern oder in die Warteschlange zu stellen und rückgängig zu machende Vorgänge zu unterstützen. Dieses Muster entkoppelt den Absender einer Anfrage von ihrem Empfänger und erleichtert so die Erweiterung und Wartung von Code.
In JavaScript können Sie das Befehlsmuster mithilfe von Objekten oder Klassen implementieren, um Befehle und Aufrufer darzustellen, die diese Befehle ausführen. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Befehlsmuster in JavaScript implementiert und verwendet wird.
Angenommen, Sie entwickeln eine Fernbedienungsanwendung für ein Smart Home und möchten eine flexible Möglichkeit zur Steuerung verschiedener Geräte schaffen.
Sie können das Befehlsmuster verwenden:
// Command interface class Command { execute() {} }
// Concrete Commands class LightOnCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.turnOn(); } }class LightOffCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.turnOff(); } }// Receiver (Device) class Light { turnOn() { console.log('Light is on.'); } turnOff() { console.log('Light is off.'); } }// Invoker (Remote Control) class RemoteControl { constructor() { this.commands = []; } addCommand(command) { this.commands.push(command); } executeCommands() { this.commands.forEach((command) => { command.execute(); }); } }// Usage const livingRoomLight = new Light(); const kitchenLight = new Light();const livingRoomLightOn = new LightOnCommand(livingRoomLight); const livingRoomLightOff = new LightOffCommand(livingRoomLight); const kitchenLightOn = new LightOnCommand(kitchenLight); const kitchenLightOff = new LightOffCommand(kitchenLight);const remoteControl = new RemoteControl();remoteControl.addCommand(livingRoomLightOn); remoteControl.addCommand(kitchenLightOff);remoteControl.executeCommands(); // Output: "Light is on." (for living room) // Output: "Light is off." (for kitchen)
In diesem Beispiel wird das Befehlsmuster verwendet, um die Aktionen zum Ein- und Ausschalten von Lichtern zu kapseln. Das RemoteControl dient als Aufrufer und konkrete Befehle (z. B. LightOnCommand und LightOffCommand) kapseln die auszuführenden Aktionen.
Das Befehlsmuster ist in verschiedenen Szenarien wertvoll, darunter:
Beachten Sie bei der Verwendung des Befehlsmusters Folgendes:
Das Zustandsmuster ist ein Verhaltensentwurfsmuster, das es einem Objekt ermöglicht, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Es kapselt Zustände als separate Klassen und delegiert das Verhalten an das aktuelle Zustandsobjekt. Dieses Muster hilft bei der Verwaltung komplexer Zustandsübergänge und fördert das „Offen-Geschlossen“-Prinzip, wodurch es einfach ist, neue Zustände hinzuzufügen, ohne vorhandenen Code zu ändern.
In JavaScript können Sie das Zustandsmuster implementieren, indem Sie Klassen zur Darstellung von Zuständen und ein Kontextobjekt verwenden, das sein Verhalten an den aktuellen Zustand delegiert. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Zustandsmuster in JavaScript implementiert und verwendet wird.
Angenommen, Sie entwickeln einen Verkaufsautomaten, der verschiedene Produkte ausgibt. Das Verhalten des Automaten hängt von seinem aktuellen Status ab, z. B. „Bereit“, „Ausgabe“ oder „Ausverkauft“. Sie können das State Pattern verwenden, um dieses Verhalten zu modellieren:
// State interface class VendingMachineState { insertMoney() {} ejectMoney() {} selectProduct() {} dispenseProduct() {} }
// Concrete States class ReadyState extends VendingMachineState { constructor(machine) { super(); this.machine = machine; } insertMoney() { console.log('Money inserted.'); this.machine.setState(this.machine.getDispensingState()); } selectProduct() { console.log('Please insert money first.'); } }class DispensingState extends VendingMachineState { constructor(machine) { super(); this.machine = machine; } dispenseProduct() { console.log('Product dispensed.'); this.machine.setState(this.machine.getReadyState()); } }class VendingMachine { constructor() { this.readyState = new ReadyState(this); this.dispensingState = new DispensingState(this); this.currentState = this.readyState; } setState(state) { this.currentState = state; } getReadyState() { return this.readyState; } getDispensingState() { return this.dispensingState; } insertMoney() { this.currentState.insertMoney(); } selectProduct() { this.currentState.selectProduct(); } dispenseProduct() { this.currentState.dispenseProduct(); } }// Usage const vendingMachine = new VendingMachine();vendingMachine.selectProduct(); // Output: "Please insert money first." vendingMachine.insertMoney(); // Output: "Money inserted." vendingMachine.dispenseProduct(); // Output: "Product dispensed."
In diesem Beispiel wird das State Pattern verwendet, um das Verhalten eines Verkaufsautomaten zu verwalten. Zustände wie „Bereit“ und „Ausgabe“ werden als separate Klassen dargestellt und der Kontext (Verkaufsautomat) delegiert sein Verhalten an den aktuellen Zustand.
Das Zustandsmuster ist in verschiedenen Szenarien wertvoll, darunter:
Berücksichtigen Sie bei der Verwendung des Statusmusters Folgendes:
Das Chain of Responsibility Pattern ist ein Verhaltensentwurfsmuster, das Ihnen hilft, eine Kette von Objekten zur Bearbeitung einer Anfrage aufzubauen. Jedes Objekt in der Kette hat die Möglichkeit, die Anfrage zu verarbeiten oder an das nächste Objekt in der Kette weiterzuleiten. Es entkoppelt den Absender einer Anfrage von seinen Empfängern und ermöglicht die Verwendung mehrerer Handler in der Kette. Dieses Muster fördert Flexibilität und Erweiterbarkeit, indem es Ihnen ermöglicht, Handler hinzuzufügen oder zu ändern, ohne den Clientcode zu beeinträchtigen.
In JavaScript können Sie das Chain of Responsibility-Muster mithilfe von Objekten oder Klassen implementieren, die Handler und einen Client darstellen, der Anforderungen initiiert. Jeder Handler hat einen Verweis auf den nächsten Handler in der Kette. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Chain of Responsibility-Muster in JavaScript implementiert und verwendet wird.
Angenommen, Sie entwickeln ein Auftragsverarbeitungssystem und möchten Bestellungen auf der Grundlage ihres Gesamtbetrags bearbeiten. Sie können das Chain of Responsibility-Muster verwenden, um eine Kette von Bearbeitern zu erstellen, die jeweils für die Bearbeitung von Bestellungen innerhalb einer bestimmten Preisspanne verantwortlich sind:
// Handler interface class OrderHandler { constructor() { this.nextHandler = null; }
setNextHandler(handler) { this.nextHandler = handler; } handleOrder(order) { if (this.canHandleOrder(order)) { this.processOrder(order); } else if (this.nextHandler) { this.nextHandler.handleOrder(order); } else { console.log('No handler can process this order.'); } } canHandleOrder(order) {} processOrder(order) {} }// Concrete Handlers class SmallOrderHandler extends OrderHandler { canHandleOrder(order) { return order.amount <= 100; } processOrder(order) { console.log(`Processing small order for ${order.amount}`); } }class MediumOrderHandler extends OrderHandler { canHandleOrder(order) { return order.amount <= 500; } processOrder(order) { console.log(`Processing medium order for ${order.amount}`); } }class LargeOrderHandler extends OrderHandler { canHandleOrder(order) { return order.amount > 500; } processOrder(order) { console.log(`Processing large order for ${order.amount}`); } }// Client class Order { constructor(amount) { this.amount = amount; } }// Usage const smallOrderHandler = new SmallOrderHandler(); const mediumOrderHandler = new MediumOrderHandler(); const largeOrderHandler = new LargeOrderHandler();smallOrderHandler.setNextHandler(mediumOrderHandler); mediumOrderHandler.setNextHandler(largeOrderHandler);const order1 = new Order(80); const order2 = new Order(250); const order3 = new Order(600);smallOrderHandler.handleOrder(order1); // Output: "Processing small order for 80" smallOrderHandler.handleOrder(order2); // Output: "Processing medium order for 250" smallOrderHandler.handleOrder(order3); // Output: "Processing large order for 600"
In diesem Beispiel wird das Chain of Responsibility-Muster verwendet, um Bestellungen unterschiedlicher Höhe abzuwickeln. Handler wie SmallOrderHandler, MediumOrderHandler und LargeOrderHandler bestimmen jeweils anhand des Bestellbetrags, ob sie eine Bestellung verarbeiten können. Wenn sie können, verarbeiten sie es; andernfalls geben sie den Befehl an den nächsten Handler in der Kette weiter.
Das Chain-of-Responsibility-Muster ist in verschiedenen Szenarien wertvoll, darunter:
Berücksichtigen Sie bei der Verwendung des Chain-of-Responsibility-Musters Folgendes:
Das Besuchermuster ist ein Verhaltensentwurfsmuster, das es Ihnen ermöglicht, einen Algorithmus von der Objektstruktur zu trennen, auf der er arbeitet. Es bietet eine Möglichkeit, neue Operationen zu Objekten hinzuzufügen, ohne deren Klassen zu ändern, und erleichtert so die Erweiterung der Funktionalität für komplexe Objekthierarchien. Dieses Muster ist besonders nützlich, wenn Sie über eine Reihe unterschiedlicher Elemente verfügen und verschiedene Vorgänge für diese ausführen möchten, ohne deren Code zu ändern.
In JavaScript können Sie das Besuchermuster mithilfe von Funktionen oder Klassen implementieren, um Besucher darzustellen, die Elemente innerhalb einer Objektstruktur besuchen. Lassen Sie uns anhand praktischer Beispiele untersuchen, wie das Besuchermuster in JavaScript implementiert und verwendet wird.
Angenommen, Sie entwickeln ein Content-Management-System mit verschiedenen Arten von Inhaltselementen wie Artikeln, Bildern und Videos. Sie möchten verschiedene Vorgänge wie Rendern und Exportieren für diese Elemente ausführen, ohne ihre Klassen zu ändern. Sie können das Besuchermuster verwenden:
// Element interface class ContentElement { accept(visitor) {} }
// Concrete Elements class Article extends ContentElement { accept(visitor) { visitor.visitArticle(this); } }class Image extends ContentElement { accept(visitor) { visitor.visitImage(this); } }class Video extends ContentElement { accept(visitor) { visitor.visitVideo(this); } }// Visitor interface class Visitor { visitArticle(article) {} visitImage(image) {} visitVideo(video) {} }// Concrete Visitors class RendererVisitor extends Visitor { visitArticle(article) { console.log(`Rendering article: ${article.title}`); } visitImage(image) { console.log(`Rendering image: ${image.caption}`); } visitVideo(video) { console.log(`Rendering video: ${video.title}`); } }class ExportVisitor extends Visitor { visitArticle(article) { console.log(`Exporting article: ${article.title}`); } visitImage(image) { console.log(`Exporting image: ${image.caption}`); } visitVideo(video) { console.log(`Exporting video: ${video.title}`); } }// Usage const elements = [new Article('Article 1'), new Image('Image 1'), new Video('Video 1')]; const renderer = new RendererVisitor(); const exporter = new ExportVisitor();elements.forEach((element) => { element.accept(renderer); element.accept(exporter); });
In diesem Beispiel haben wir Inhaltselemente wie Artikel, Bild und Video und möchten Rendering- und Exportvorgänge für sie durchführen, ohne ihre Klassen zu ändern. Dies erreichen wir durch die Implementierung von Besucherklassen wie RendererVisitor und ExportVisitor, die die Elemente besuchen und die gewünschten Vorgänge ausführen.
Das Besuchermuster ist in verschiedenen Szenarien wertvoll, darunter:
Berücksichtigen Sie bei der Verwendung des Besuchermusters Folgendes:
In dieser umfassenden Untersuchung von Entwurfsmustern in JavaScript haben wir uns mit verschiedenen Mustern befasst, die es Entwicklern ermöglichen, flexiblen, wartbaren und effizienten Code zu erstellen. Jedes Entwurfsmuster befasst sich mit spezifischen Problemen und bietet elegante Lösungen für häufige Software-Design-Herausforderungen.
Wir begannen mit dem Verständnis des grundlegenden Konzepts von Designmustern und kategorisierten sie in drei Hauptgruppen: Schöpfungs-, Struktur- und Verhaltensmuster. In jeder Kategorie haben wir beliebte Designmuster untersucht und ihre praktischen Implementierungen in JavaScript vorgestellt.
Hier ist eine kurze Zusammenfassung der wichtigsten Designmuster, die wir behandelt haben:
Erstellungsmuster: Diese Muster konzentrieren sich auf Objekterstellungsmechanismen, einschließlich des Singleton-Musters zur Sicherstellung einer einzelnen Instanz einer Klasse, Factory- und Abstract Factory-Mustern zum Erstellen von Objekten mit flexiblen Fabriken, Builder-Muster zum schrittweisen Konstruieren komplexer Objekte und Prototype-Muster zum Klonen Objekte und Object Pool Pattern für eine effiziente Wiederverwendung von Objekten.
Strukturmuster: Diese Muster befassen sich mit der Objektzusammensetzung und bieten Möglichkeiten zum Aufbau komplexer Strukturen aus einfacheren Komponenten. Wir haben das Adaptermuster zum Anpassen von Schnittstellen, das Dekoratormuster zum dynamischen Hinzufügen von Verhalten zu Objekten, das Proxymuster zum Steuern des Zugriffs auf Objekte, das zusammengesetzte Muster zum Zusammenstellen von Objekten in Baumstrukturen, das Brückenmuster zum Trennen von Abstraktion und Implementierung und das Fliegengewicht untersucht Muster zur Minimierung der Speichernutzung durch gemeinsame Nutzung des gemeinsamen Status.
Verhaltensmuster: Diese Muster befassen sich mit der Interaktion und Kommunikation zwischen Objekten. Wir haben das Observer-Muster zum Implementieren verteilter Ereignisverarbeitungssysteme, das Strategiemuster zum Kapseln austauschbarer Algorithmen, das Befehlsmuster zum Umwandeln von Anforderungen in eigenständige Objekte, das Statusmuster zum Verwalten des Objektverhaltens basierend auf dem internen Status und das Verantwortungskettenmuster zum Erstellen eines behandelt Kette von Handlern zur Verarbeitung von Anfragen und das Besuchermuster zur Trennung von Algorithmen von Objektstrukturen.
Entwurfsmuster sind wertvolle Werkzeuge im Toolkit eines Entwicklers und ermöglichen die Erstellung skalierbarer und wartbarer Codebasen. Wenn Sie diese Muster verstehen und in Ihren JavaScript-Projekten anwenden, können Sie effizientere, anpassungsfähigere und robustere Software schreiben.
Denken Sie daran, dass Entwurfsmuster keine Einheitslösungen sind und ihre Anwendbarkeit von den spezifischen Anforderungen und Herausforderungen Ihres Projekts abhängt. Überlegen Sie sorgfältig, wann und wie Sie sie anwenden, um die besten Ergebnisse zu erzielen.
Während Sie sich als JavaScript-Entwickler weiterentwickeln, werden Sie durch die Beherrschung dieser Entwurfsmuster in die Lage versetzt, komplexe Software-Design-Herausforderungen mit Zuversicht und Kreativität anzugehen. Unabhängig davon, ob Sie Webanwendungen, Spiele-Engines oder andere Software erstellen, sind Entwurfsmuster Ihre Verbündeten bei der Erstellung eleganten und wartbaren Codes. Viel Spaß beim Codieren!
Auch hier veröffentlicht.