{"id":58809,"date":"2023-02-14T09:27:38","date_gmt":"2023-02-14T08:27:38","guid":{"rendered":"https:\/\/kinsta.com\/de\/?p=58809&#038;preview=true&#038;preview_id=58809"},"modified":"2023-07-27T11:07:59","modified_gmt":"2023-07-27T10:07:59","slug":"javascript-entwurfsmuster","status":"publish","type":"post","link":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/","title":{"rendered":"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern"},"content":{"rendered":"<p>Bei der Erstellung von <a href=\"https:\/\/kinsta.com\/de\/blog\/was-ist-javascript\/\">JavaScript<\/a>-Anwendungen kann es vorkommen, dass du Objekte auf eine bestimmte, vordefinierte Art und Weise erstellen oder eine gemeinsame Klasse wiederverwenden musst, indem du sie f\u00fcr mehrere Anwendungsf\u00e4lle modifizierst oder anpasst.<\/p>\n<p>Es ist nat\u00fcrlich nicht bequem, diese Probleme immer wieder zu l\u00f6sen.<\/p>\n<p>Hier kommen die JavaScript Design Patterns zu deiner Rettung.<\/p>\n\n<p>JavaScript-Entwurfsmuster bieten dir eine strukturierte, wiederholbare Methode, um h\u00e4ufig auftretende Probleme bei der JavaScript-Entwicklung zu l\u00f6sen.<\/p>\n<p>In diesem Leitfaden werden wir einen Blick darauf werfen, was JavaScript Design Patterns sind und wie du sie in deinen JavaScript-Anwendungen einsetzen kannst.<div><\/div><kinsta-auto-toc heading=\"Table of Contents\" exclude=\"last\" list-style=\"arrow\" selector=\"h2\" count-number=\"-1\"><\/kinsta-auto-toc><\/p>\n<h2>Was ist ein JavaScript Entwurfsmuster?<\/h2>\n<p>JavaScript-Entwurfsmuster sind wiederholbare Musterl\u00f6sungen f\u00fcr h\u00e4ufig auftretende Probleme bei der Entwicklung von JavaScript-Anwendungen.<\/p>\n<p>Die Idee ist einfach: Programmiererinnen und Programmierer auf der ganzen Welt sind seit den Anf\u00e4ngen der <a href=\"https:\/\/kinsta.com\/de\/blog\/anwendungsentwickler\/\">Entwicklung von Apps<\/a> mit immer wiederkehrenden Problemen konfrontiert. Im Laufe der Zeit haben sich einige Entwickler\/innen dazu entschlossen, erprobte Wege zur L\u00f6sung dieser Probleme zu dokumentieren, damit andere auf diese L\u00f6sungen zur\u00fcckgreifen k\u00f6nnen.<\/p>\n<p>Als immer mehr Entwickler diese L\u00f6sungen nutzten und ihre Effizienz bei der L\u00f6sung ihrer Probleme erkannten, wurden sie als Standardmethode zur Probleml\u00f6sung akzeptiert und erhielten den Namen &#8222;Design Patterns&#8220;.<\/p>\n<p>Als die Bedeutung von Entwurfsmustern immer besser verstanden wurde, wurden sie weiterentwickelt und standardisiert. Die meisten modernen Entwurfsmuster haben heute eine definierte Struktur, sind in mehreren Kategorien organisiert und werden in Informatikstudieng\u00e4ngen als eigenst\u00e4ndige Themen gelehrt.<\/p>\n<h2>Arten von JavaScript Entwurfsmuster<\/h2>\n<p>Hier sind einige der g\u00e4ngigsten Klassifizierungen von JavaScript-Entwurfsmustern.<\/p>\n<h3>Kreative<\/h3>\n<p>Kreative Entwurfsmuster helfen, Probleme bei der Erstellung und Verwaltung neuer Objektinstanzen in JavaScript zu l\u00f6sen. Das kann so einfach sein wie die Beschr\u00e4nkung einer Klasse auf ein einziges Objekt oder so komplex wie die Definition einer komplizierten Methode zur Auswahl und Hinzuf\u00fcgung jeder Funktion in einem JavaScript-Objekt.<\/p>\n<p>Einige Beispiele f\u00fcr kreative Entwurfsmuster sind Singleton, Factory, Abstract Factory und Builder, um nur einige zu nennen.<\/p>\n<h3>Strukturelle<\/h3>\n<p>Strukturelle Entwurfsmuster helfen dabei, Probleme bei der Verwaltung der Struktur (oder des Schemas) von JavaScript-Objekten zu l\u00f6sen. Diese Probleme k\u00f6nnen darin bestehen, eine Beziehung zwischen zwei ungleichen Objekten herzustellen oder einige Eigenschaften eines Objekts f\u00fcr bestimmte Benutzer zu abstrahieren.<\/p>\n<p>Ein paar Beispiele f\u00fcr strukturelle Entwurfsmuster sind Adapter, Bridge, Composite und Facade.<\/p>\n<h3>Verhalten<\/h3>\n<p>Verhaltensmuster helfen bei der L\u00f6sung von Problemen, bei denen es darum geht, wie die Kontrolle (und Verantwortung) zwischen verschiedenen Objekten weitergegeben wird. Bei diesen Problemen geht es z. B. darum, den Zugriff auf eine verkn\u00fcpfte Liste zu kontrollieren oder eine einzige Instanz einzurichten, die den Zugriff auf mehrere Arten von Objekten kontrollieren kann.<\/p>\n<p>Einige Beispiele f\u00fcr verhaltensorientierte Entwurfsmuster sind Command, Iterator, Memento und Observer.<\/p>\n<h3>Gleichzeitigkeit<\/h3>\n<p>Gleichzeitige Entwurfsmuster helfen, Probleme im Zusammenhang mit Multithreading und Multitasking zu l\u00f6sen. Diese Probleme k\u00f6nnen darin bestehen, ein aktives Objekt unter mehreren verf\u00fcgbaren Objekten aufrechtzuerhalten oder mehrere Ereignisse zu verarbeiten, die einem System zugef\u00fchrt werden, indem eingehende Eingaben demultiplexiert und St\u00fcck f\u00fcr St\u00fcck verarbeitet werden.<\/p>\n<p>Einige Beispiele f\u00fcr Gleichzeitigkeits-Designmuster sind Active Object, Nuclear React und Scheduler.<\/p>\n<h3>Architektonische<\/h3>\n<p>Architektonische Entwurfsmuster helfen bei der L\u00f6sung von Problemen rund um das <a href=\"https:\/\/kinsta.com\/de\/blog\/web-anwendungs-architektur\/\">Softwaredesign<\/a> im weitesten Sinne. Sie beziehen sich in der Regel darauf, wie du dein System konzipierst, um eine hohe Verf\u00fcgbarkeit zu gew\u00e4hrleisten, Risiken zu minimieren und <a href=\"https:\/\/kinsta.com\/de\/blog\/application-performance-monitoring\/\">Leistungsengp\u00e4sse zu vermeiden<\/a>.<\/p>\n<p>Zwei Beispiele f\u00fcr architektonische Entwurfsmuster sind MVC und MVVM.<\/p>\n<h2>Elemente eines Entwurfsmusters<\/h2>\n<p>Fast alle Design Pattern lassen sich in vier wichtige Komponenten unterteilen. Sie sind:<\/p>\n<ul>\n<li><strong>Name des Musters<\/strong>: Er wird verwendet, um ein Entwurfsmuster bei der Kommunikation mit anderen Benutzern zu identifizieren. Beispiele sind &#8222;Singleton&#8220;, &#8222;Prototyp&#8220; und andere.<\/li>\n<li><strong>Problem<\/strong>: Hier wird das Ziel des Entwurfsmusters beschrieben. Es ist eine kurze Beschreibung des Problems, das das Entwurfsmuster zu l\u00f6sen versucht. Es kann sogar ein Beispielszenario enthalten, um das Problem besser zu erkl\u00e4ren. Sie kann auch eine Liste von Bedingungen enthalten, die erf\u00fcllt sein m\u00fcssen, damit ein Entwurfsmuster das Problem vollst\u00e4ndig l\u00f6st.<\/li>\n<li><strong>L\u00f6sung<\/strong>: Dies ist die L\u00f6sung des Problems, die aus Elementen wie Klassen, Methoden, Schnittstellen usw. besteht. Hier liegt der Hauptteil eines Entwurfsmusters &#8211; es beinhaltet Beziehungen, Verantwortlichkeiten und Mitwirkende der verschiedenen Elemente, die klar definiert sind.<\/li>\n<li><strong>Ergebnisse<\/strong>: Hier wird analysiert, wie gut das Muster das Problem l\u00f6sen konnte. Dabei werden Aspekte wie Platz- und Zeitbedarf sowie alternative L\u00f6sungsans\u00e4tze f\u00fcr das gleiche Problem diskutiert.<\/li>\n<\/ul>\n<p>Wenn du mehr \u00fcber Design Patterns und ihre Entstehung erfahren m\u00f6chtest, findest du an der MSU <a href=\"https:\/\/www.cse.msu.edu\/~cse870\/Lectures\/SS2005\/08-design-patterns.ppt\">kurzes Studienmaterial<\/a>, auf das du zur\u00fcckgreifen kannst.<\/p>\n<h2>Warum solltest du Entwurfsmuster verwenden?<\/h2>\n<p>Es gibt viele Gr\u00fcnde, warum du Design Patterns verwenden solltest:<\/p>\n<ul>\n<li><strong>Sie sind erprobt und bew\u00e4hrt<\/strong>: Mit einem Entwurfsmuster hast du eine erprobte L\u00f6sung f\u00fcr dein Problem (vorausgesetzt, das Entwurfsmuster passt zur Beschreibung deines Problems). Du musst keine Zeit mit der Suche nach alternativen L\u00f6sungen verschwenden und kannst dich darauf verlassen, dass du eine L\u00f6sung hast, die die grundlegende Leistungsoptimierung f\u00fcr dich \u00fcbernimmt.<\/li>\n<li><strong>Sie sind leicht zu verstehen<\/strong>: Design Patterns sollen klein, einfach und leicht zu verstehen sein. Du musst kein spezialisierter Programmierer sein, der seit Jahrzehnten in einer bestimmten Branche arbeitet, um zu verstehen, welches Entwurfsmuster du verwenden solltest. Sie sind bewusst allgemein gehalten (nicht auf eine bestimmte Programmiersprache beschr\u00e4nkt) und k\u00f6nnen von jedem verstanden werden, der \u00fcber ausreichende Probleml\u00f6sungsf\u00e4higkeiten verf\u00fcgt. Das ist auch hilfreich, wenn du einen Wechsel in deinem technischen Team hast: Ein Code, der auf einem Entwurfsmuster basiert, ist f\u00fcr jeden neuen Softwareentwickler leichter zu verstehen.<\/li>\n<\/ul>\n<ul>\n<li><strong>Sie sind einfach zu implementieren<\/strong>: Die meisten Entwurfsmuster sind sehr einfach, wie du sp\u00e4ter in unserem Artikel sehen wirst. Du musst nicht viele <a href=\"https:\/\/kinsta.com\/de\/blog\/objektorientierten-programmierung-python\/\">Programmierkonzepte<\/a> kennen, um sie in deinem Code zu implementieren.<\/li>\n<\/ul>\n<ul>\n<li><strong>Sie schlagen eine Code-Architektur vor, die leicht wiederverwendbar ist<\/strong>: Wiederverwendbarkeit und <a href=\"https:\/\/kinsta.com\/de\/blog\/bewaehrte-html-praktiken\/\">Sauberkeit des Codes<\/a> werden in der gesamten Tech-Branche stark gef\u00f6rdert, und Design Patterns k\u00f6nnen dir dabei helfen, dies zu erreichen. Da es sich bei diesen Mustern um eine Standardl\u00f6sung f\u00fcr Probleme handelt, haben die Designer darauf geachtet, dass die gesamte App-Architektur wiederverwendbar, flexibel und mit den meisten Formen der Codeerstellung kompatibel ist.<\/li>\n<\/ul>\n<ul>\n<li><strong>Sie sparen Zeit und die Gr\u00f6\u00dfe der App<\/strong>: Einer der gr\u00f6\u00dften Vorteile, wenn du dich auf Standardl\u00f6sungen verl\u00e4sst, ist, dass du bei der Implementierung Zeit sparen kannst. Die Wahrscheinlichkeit ist gro\u00df, dass dein gesamtes Entwicklungsteam die Design Patterns gut kennt, so dass es f\u00fcr sie einfacher ist, bei der Implementierung <a href=\"https:\/\/kinsta.com\/de\/blog\/microsoft-teams-vs-slack\/\">zu planen, zu kommunizieren und zusammenzuarbeiten<\/a>. Bei erprobten und getesteten L\u00f6sungen ist die Wahrscheinlichkeit gro\u00df, dass du bei der Entwicklung einer Funktion keine Ressourcen verschwendest oder einen Umweg gehst, was dir Zeit und Platz spart. Au\u00dferdem bieten die meisten <a href=\"https:\/\/kinsta.com\/de\/blog\/beste-programmiersprache-lernen-sollte\/\">Programmiersprachen<\/a> Standardvorlagenbibliotheken, die bereits einige g\u00e4ngige Entwurfsmuster wie Iterator und Observer implementieren.<\/li>\n<\/ul>\n<h2>Die 20 wichtigsten JavaScript Entwurfsmuster, die du beherrschen solltest<\/h2>\n<p>Jetzt, wo du wei\u00dft, woraus ein Entwurfsmuster besteht und warum du sie brauchst, wollen wir uns genauer ansehen, wie einige der am h\u00e4ufigsten verwendeten JavaScript-Entwurfsmuster in einer <a href=\"https:\/\/kinsta.com\/de\/blog\/node-js-apps\/\">JavaScript-App<\/a> implementiert werden k\u00f6nnen.<\/p>\n<h3>Kreation<\/h3>\n<p>Beginnen wir die Diskussion mit einigen grundlegenden, leicht zu erlernenden kreativen Entwurfsmustern.<\/p>\n<h4>1. Singleton<\/h4>\n<p>Das Singleton-Muster ist eines der am h\u00e4ufigsten verwendeten Entwurfsmuster in der Softwareentwicklungsbranche. Das Problem, das es l\u00f6sen soll, ist, dass nur eine einzige Instanz einer Klasse vorhanden ist. Dies kann bei der Instanziierung von ressourcenintensiven Objekten, wie z. B. Datenbank-Handlern, sehr n\u00fctzlich sein.<\/p>\n<p>Hier erf\u00e4hrst du, wie du es in JavaScript umsetzen kannst:<\/p>\n<pre><code class=\"language-js\">function SingletonFoo() {\n\n   let fooInstance = null;\n\n   \/\/ For our reference, let's create a counter that will track the number of active instances\n   let count = 0;\n\n   function printCount() {\n       console.log(\"Number of instances: \" + count);\n   }\n\n   function init() {\n       \/\/ For our reference, we'll increase the count by one whenever init() is called\n       count++;\n\n       \/\/ Do the initialization of the resource-intensive object here and return it\n       return {}\n   }\n\n   function createInstance() {\n       if (fooInstance == null) {\n           fooInstance = init();\n       }\n       return fooInstance;\n   }\n\n   function closeInstance() {\n       count--;\n       fooInstance = null;\n   }\n\n   return {\n       initialize: createInstance,\n       close: closeInstance,\n       printCount: printCount\n   }\n}\n\nlet foo = SingletonFoo();\n\nfoo.printCount() \/\/ Prints 0\nfoo.initialize()\nfoo.printCount() \/\/ Prints 1\nfoo.initialize()\nfoo.printCount() \/\/ Still prints 1\nfoo.initialize()\nfoo.printCount() \/\/ Still 1\nfoo.close()\nfoo.printCount() \/\/ Prints 0<\/code><\/pre>\n<p>Das Singleton-Muster erf\u00fcllt zwar seinen Zweck, ist aber daf\u00fcr bekannt, dass es die Fehlersuche erschwert, da es Abh\u00e4ngigkeiten verschleiert und den Zugriff auf die Initialisierung oder Zerst\u00f6rung von Klasseninstanzen kontrolliert.<\/p>\n<h4>2. Factory<\/h4>\n<p>Die Factory-Methode ist ebenfalls eines der beliebtesten Entwurfsmuster. Das Problem, das mit der Factory-Methode gel\u00f6st werden soll, ist die Erstellung von Objekten, ohne den herk\u00f6mmlichen Konstruktor zu verwenden. Stattdessen nimmt sie die Konfiguration (oder Beschreibung) des gew\u00fcnschten Objekts auf und gibt das neu erstellte Objekt zur\u00fcck.<\/p>\n<p>Hier siehst du, wie du sie in JavaScript implementieren kannst:<\/p>\n<pre><code class=\"language-js\">function Factory() {\n   this.createDog = function (breed) {\n       let dog;\n\n       if (breed === \"labrador\") {\n           dog = new Labrador();\n       } else if (breed === \"bulldog\") {\n           dog = new Bulldog();\n       } else if (breed === \"golden retriever\") {\n           dog = new GoldenRetriever();\n       } else if (breed === \"german shepherd\") {\n           dog = new GermanShepherd();\n       }\n\n       dog.breed = breed;\n       dog.printInfo = function () {\n           console.log(\"nnBreed: \" + dog.breed + \"nShedding Level (out of 5): \" + dog.sheddingLevel + \"nCoat Length: \" + dog.coatLength + \"nCoat Type: \" + dog.coatType)\n       }\n\n       return dog;\n   }\n}\n\nfunction Labrador() {\n   this.sheddingLevel = 4\n   this.coatLength = \"short\"\n   this.coatType = \"double\"\n}\n\nfunction Bulldog() {\n   this.sheddingLevel = 3\n   this.coatLength = \"short\"\n   this.coatType = \"smooth\"\n}\n\nfunction GoldenRetriever() {\n   this.sheddingLevel = 4\n   this.coatLength = \"medium\"\n   this.coatType = \"double\"\n}\n\nfunction GermanShepherd() {\n   this.sheddingLevel = 4\n   this.coatLength = \"medium\"\n   this.coatType = \"double\"\n}\n\nfunction run() {\n\n   let dogs = [];\n   let factory = new Factory();\n\n   dogs.push(factory.createDog(\"labrador\"));\n   dogs.push(factory.createDog(\"bulldog\"));\n   dogs.push(factory.createDog(\"golden retriever\"));\n   dogs.push(factory.createDog(\"german shepherd\"));\n\n   for (var i = 0, len = dogs.length; i &lt; len; i++) {\n       dogs[i].printInfo();\n   }\n}\n\nrun()\n\n\/**\nOutput:\n\nBreed: labrador\nShedding Level (out of 5): 4\nCoat Length: short\nCoat Type: double\n\n\nBreed: bulldog\nShedding Level (out of 5): 3\nCoat Length: short\nCoat Type: smooth\n\n\nBreed: golden retriever\nShedding Level (out of 5): 4\nCoat Length: medium\nCoat Type: double\n\n\nBreed: german shepherd\nShedding Level (out of 5): 4\nCoat Length: medium\nCoat Type: double\n*\/<\/code><\/pre>\n<p>Das Factory-Designmuster steuert, wie die Objekte erstellt werden, und bietet dir eine schnelle M\u00f6glichkeit, neue Objekte zu erstellen, sowie eine einheitliche Schnittstelle, die die Eigenschaften deiner Objekte definiert. Du kannst so viele Hunderassen hinzuf\u00fcgen, wie du willst, aber solange die Methoden und Eigenschaften, die die einzelnen Rassen aufweisen, gleich bleiben, werden sie einwandfrei funktionieren.<\/p>\n<p>Beachte jedoch, dass das Factory-Muster oft zu einer gro\u00dfen Anzahl von Klassen f\u00fchrt, die schwer zu verwalten sind.<\/p>\n<h4>3. Abstract Factory<\/h4>\n<p>Die Abstract Factory-Methode hebt die Factory-Methode auf eine h\u00f6here Ebene, indem sie Factories abstrakt und damit austauschbar macht, ohne dass die aufrufende Umgebung die genaue verwendete Factory oder deren interne Funktionsweise kennt. Die aufrufende Umgebung wei\u00df nur, dass alle Factories eine Reihe gemeinsamer Methoden haben, die sie aufrufen kann, um die Instanziierung vorzunehmen.<\/p>\n<p>So kann es mit dem vorherigen Beispiel umgesetzt werden:<\/p>\n<pre><code class=\"language-js\">\/\/ A factory to create dogs\nfunction DogFactory() {\n   \/\/ Notice that the create function is now createPet instead of createDog, since we need\n   \/\/ it to be uniform across the other factories that will be used with this\n   this.createPet = function (breed) {\n       let dog;\n\n       if (breed === \"labrador\") {\n           dog = new Labrador();\n       } else if (breed === \"pug\") {\n           dog = new Pug();\n       }\n\n       dog.breed = breed;\n       dog.printInfo = function () {\n           console.log(\"nnType: \" + dog.type + \"nBreed: \" + dog.breed + \"nSize: \" + dog.size)\n       }\n\n       return dog;\n   }\n}\n\n\/\/ A factory to create cats\nfunction CatFactory() {\n   this.createPet = function (breed) {\n       let cat;\n\n       if (breed === \"ragdoll\") {\n           cat = new Ragdoll();\n       } else if (breed === \"singapura\") {\n           cat = new Singapura();\n       }\n\n       cat.breed = breed;\n       cat.printInfo = function () {\n           console.log(\"nnType: \" + cat.type + \"nBreed: \" + cat.breed + \"nSize: \" + cat.size)\n       }\n\n       return cat;\n   }\n}\n\n\/\/ Dog and cat breed definitions\nfunction Labrador() {\n   this.type = \"dog\"\n   this.size = \"large\"\n}\n\nfunction Pug() {\n   this.type = \"dog\"\n   this.size = \"small\"\n}\n\nfunction Ragdoll() {\n   this.type = \"cat\"\n   this.size = \"large\"\n}\n\nfunction Singapura() {\n   this.type = \"cat\"\n   this.size = \"small\"\n}\n\nfunction run() {\n\n   let pets = [];\n\n   \/\/ Initialize the two factories\n   let catFactory = new CatFactory();\n   let dogFactory = new DogFactory();\n\n   \/\/ Create a common petFactory that can produce both cats and dogs\n   \/\/ Set it to produce dogs first\n   let petFactory = dogFactory;\n\n   pets.push(petFactory.createPet(\"labrador\"));\n   pets.push(petFactory.createPet(\"pug\"));\n\n   \/\/ Set the petFactory to produce cats\n   petFactory = catFactory;\n\n   pets.push(petFactory.createPet(\"ragdoll\"));\n   pets.push(petFactory.createPet(\"singapura\"));\n\n   for (var i = 0, len = pets.length; i &lt; len; i++) {\n       pets[i].printInfo();\n   }\n}\n\nrun()\n\n\/**\nOutput:\n\nType: dog\nBreed: labrador\nSize: large\n\n\nType: dog\nBreed: pug\nSize: small\n\n\nType: cat\nBreed: ragdoll\nSize: large\n\n\nType: cat\nBreed: singapura\nSize: small\n\n*\/<\/code><\/pre>\n<p>Das Muster der abstract Factories erleichtert den Austausch konkreter Factories und f\u00f6rdert die Einheitlichkeit der Fabriken und der erzeugten Produkte. Allerdings kann es schwierig werden, neue Arten von Produkten einzuf\u00fchren, da du in mehreren Klassen \u00c4nderungen vornehmen musst, um neue Methoden\/Eigenschaften unterzubringen.<\/p>\n<h4>4. Builder<\/h4>\n<p>Das Builder-Muster ist eines der komplexesten und gleichzeitig flexibelsten JavaScript-Designmuster. Es erm\u00f6glicht es dir, jedes Feature einzeln in dein Produkt einzubauen. So hast du die volle Kontrolle \u00fcber den Aufbau deines Objekts und kannst gleichzeitig von den internen Details abstrahieren.<\/p>\n<p>In dem komplizierten Beispiel unten siehst du das Builder Design Pattern in Aktion zusammen mit Director, um Pizzas zu machen!<\/p>\n<pre><code class=\"language-js\">\/\/ Here's the PizzaBuilder (you can also call it the chef)\nfunction PizzaBuilder() {\n   let base\n   let sauce\n   let cheese\n   let toppings = []\n\n   \/\/ The definition of pizza is hidden from the customers\n   function Pizza(base, sauce, cheese, toppings) {\n       this.base = base\n       this.sauce = sauce\n       this.cheese = cheese\n       this.toppings = toppings\n\n       this.printInfo = function() {\n           console.log(\"This pizza has \" + this.base + \" base with \" + this.sauce + \" sauce \"\n           + (this.cheese !== undefined ? \"with cheese. \" : \"without cheese. \")\n           + (this.toppings.length !== 0 ? \"It has the following toppings: \" + toppings.toString() : \"\"))\n       }\n   }\n\n   \/\/ You can request the PizzaBuilder (\/chef) to perform any of the following actions on your pizza\n   return {\n       addFlatbreadBase: function() {\n           base = \"flatbread\"\n           return this;\n       },\n       addTomatoSauce: function() {\n           sauce = \"tomato\"\n           return this;\n       },\n       addAlfredoSauce: function() {\n           sauce = \"alfredo\"\n           return this;\n       },\n       addCheese: function() {\n           cheese = \"parmesan\"\n           return this;\n       },\n       addOlives: function() {\n           toppings.push(\"olives\")\n           return this\n       },\n       addJalapeno: function() {\n           toppings.push(\"jalapeno\")\n           return this\n       },\n       cook: function() {\n           if (base === null){\n               console.log(\"Can't make a pizza without a base\")\n               return\n           }\n           return new Pizza(base, sauce, cheese, toppings)\n       }\n   }\n\n}\n\n\/\/ This is the Director for the PizzaBuilder, aka the PizzaShop.\n\/\/ It contains a list of preset steps that can be used to prepare common pizzas (aka recipes!)\nfunction PizzaShop() {\n   return {\n       makePizzaMargherita: function() {\n           pizzaBuilder = new PizzaBuilder()\n           pizzaMargherita = pizzaBuilder.addFlatbreadBase().addTomatoSauce().addCheese().addOlives().cook()\n           return pizzaMargherita\n       },\n       makePizzaAlfredo: function() {\n           pizzaBuilder = new PizzaBuilder()\n           pizzaAlfredo = pizzaBuilder.addFlatbreadBase().addAlfredoSauce().addCheese().addJalapeno().cook()\n           return pizzaAlfredo\n       },\n       makePizzaMarinara: function() {\n           pizzaBuilder = new PizzaBuilder()\n           pizzaMarinara = pizzaBuilder.addFlatbreadBase().addTomatoSauce().addOlives().cook()\n           return pizzaMarinara\n       }\n   }\n}\n\n\/\/ Here's where the customer can request pizzas from\nfunction run() {\n\n   let pizzaShop = new PizzaShop()\n\n   \/\/ You can ask for one of the popular pizza recipes...\n   let pizzaMargherita = pizzaShop.makePizzaMargherita()\n   pizzaMargherita.printInfo()\n   \/\/ Output: This pizza has flatbread base with tomato sauce with cheese. It has the following toppings: olives\n\n   let pizzaAlfredo = pizzaShop.makePizzaAlfredo()\n   pizzaAlfredo.printInfo()\n   \/\/ Output: This pizza has flatbread base with alfredo sauce with cheese. It has the following toppings: jalapeno\n\n   let pizzaMarinara = pizzaShop.makePizzaMarinara()\n   pizzaMarinara.printInfo()\n   \/\/ Output: This pizza has flatbread base with tomato sauce without cheese. It has the following toppings: olives\n\n   \/\/ Or send your custom request directly to the chef!\n   let chef = PizzaBuilder()\n   let customPizza = chef.addFlatbreadBase().addTomatoSauce().addCheese().addOlives().addJalapeno().cook()\n   customPizza.printInfo()\n   \/\/ Output: This pizza has flatbread base with tomato sauce with cheese. It has the following toppings: olives,jalapeno\n\n}\n\nrun()<\/code><\/pre>\n<p>Du kannst den Builder mit einem Director koppeln, wie die Klasse <code>PizzaShop<\/code> im obigen Beispiel zeigt, um eine Reihe von Schritten vorzugeben, die du jedes Mal befolgen musst, um eine Standardvariante deines Produkts zu erstellen, z. B. ein bestimmtes Rezept f\u00fcr deine Pizzen.<\/p>\n<p>Der einzige Nachteil dieses Entwurfsmusters ist, dass es ziemlich komplex in der Einrichtung und Pflege ist. Das Hinzuf\u00fcgen neuer Funktionen ist auf diese Weise jedoch einfacher als die Factory-Methode.<\/p>\n<h4>5. Prototyp<\/h4>\n<p>Das Entwurfsmuster Prototype ist eine schnelle und einfache Methode, um neue Objekte aus bestehenden Objekten zu erstellen, indem man sie klont.<\/p>\n<p>Zun\u00e4chst wird ein Prototyp-Objekt erstellt, das mehrfach geklont werden kann, um neue Objekte zu erstellen. Es ist praktisch, wenn die direkte Instanziierung eines Objekts ressourcenintensiver ist als die Erstellung einer Kopie eines bestehenden Objekts.<\/p>\n<p>Im folgenden Beispiel siehst du, wie du das Prototyp-Muster verwenden kannst, um neue Dokumente auf der Grundlage einer vorgegebenen Dokumentvorlage zu erstellen:<\/p>\n<pre><code class=\"language-js\">\/\/ Defining how a document would look like\nfunction Document() {\n   this.header = \"Acme Co\"\n   this.footer = \"For internal use only\"\n   this.pages = 2\n   this.text = \"\"\n  \n   this.addText = function(text) {\n       this.text += text\n   }\n\n   \/\/ Method to help you see the contents of the object\n   this.printInfo = function() {\n       console.log(\"nnHeader: \" + this.header + \"nFooter: \" + this.footer + \"nPages: \" + this.pages + \"nText: \" + this.text)\n   }\n\n  \n}\n\n\/\/ A protype (or template) for creating new blank documents with boilerplate information\nfunction DocumentPrototype(baseDocument) {\n   this.baseDocument = baseDocument\n  \n   \/\/ This is where the magic happens. A new document object is created and is assigned the values of the current object\n   this.clone = function() {\n       let document = new Document();\n\n       document.header = this.baseDocument.header\n       document.footer = this.baseDocument.footer\n       document.pages = this.baseDocument.pages\n       document.text = this.baseDocument.text\n\n       return document\n   }\n}\n\nfunction run() {\n   \/\/ Create a document to use as the base for the prototype\n   let baseDocument = new Document()\n\n   \/\/ Make some changes to the prototype\n   baseDocument.addText(\"This text was added before cloning and will be common in both documents. \")\n\n   let prototype = new DocumentPrototype(baseDocument)\n\n   \/\/ Create two documents from the prototype\n   let doc1 = prototype.clone()\n   let doc2 = prototype.clone()\n\n   \/\/ Make some changes to both objects\n   doc1.pages = 3\n\n   doc1.addText(\"This is document 1\")\n   doc2.addText(\"This is document 2\")\n\n   \/\/ Print their values\n   doc1.printInfo()\n   \/* Output:\n       Header: Acme Co\n       Footer: For internal use only\n       Pages: 3\n       Text: This text was added before cloning and will be common in both documents. This is document 1\n    *\/\n\n   doc2.printInfo()\n   \/** Output:\n       Header: Acme Co\n       Footer: For internal use only\n       Pages: 2\n       Text: This text was added before cloning and will be common in both documents. This is document 2\n    *\/\n}\n\nrun()<\/code><\/pre>\n<p>Die Prototyp-Methode eignet sich gut f\u00fcr F\u00e4lle, in denen ein gro\u00dfer Teil deiner Objekte die gleichen Werte hat oder wenn die Erstellung eines neuen Objekts sehr kostspielig ist. In F\u00e4llen, in denen du nicht mehr als ein paar Instanzen der Klasse brauchst, ist sie jedoch zu aufwendig.<\/p>\n<h3>Strukturelle<\/h3>\n<p>Strukturelle Entwurfsmuster helfen dir dabei, deine Gesch\u00e4ftslogik zu organisieren, indem sie bew\u00e4hrte Wege zur Strukturierung deiner Klassen aufzeigen. Es gibt eine Vielzahl von strukturellen Entwurfsmustern, die jeweils auf bestimmte Anwendungsf\u00e4lle zugeschnitten sind.<\/p>\n<h4>6. Adapter<\/h4>\n<p>Ein h\u00e4ufiges Problem bei der Entwicklung von Anwendungen ist die Zusammenarbeit zwischen inkompatiblen Klassen.<\/p>\n<p>Ein gutes Beispiel, um das zu verstehen, ist die Aufrechterhaltung der Abw\u00e4rtskompatibilit\u00e4t. Wenn du eine neue Version einer Klasse schreibst, m\u00f6chtest du nat\u00fcrlich, dass sie an allen Stellen, an denen die alte Version funktionierte, problemlos verwendet werden kann. Wenn du jedoch \u00c4nderungen vornimmst, wie z. B. das Entfernen oder Aktualisieren von Methoden, die f\u00fcr das Funktionieren der alten Version entscheidend waren, kann es passieren, dass du eine Klasse bekommst, deren Clients alle aktualisiert werden m\u00fcssen, um sie ausf\u00fchren zu k\u00f6nnen.<\/p>\n<p>In solchen F\u00e4llen kann das Adapter Design Pattern helfen.<\/p>\n<p>Das Adapter-Entwurfsmuster bietet dir eine Abstraktion, die die Kluft zwischen den Methoden und Eigenschaften der neuen Klasse und den Methoden und Eigenschaften der alten Klasse \u00fcberbr\u00fcckt. Sie hat dieselbe Schnittstelle wie die alte Klasse, enth\u00e4lt aber eine Logik, mit der die alten Methoden auf die neuen Methoden abgebildet werden, um \u00e4hnliche Vorg\u00e4nge auszuf\u00fchren. Dies ist vergleichbar mit einer Steckdose, die als Adapter zwischen einem US-amerikanischen und einem europ\u00e4ischen Stecker fungiert.<\/p>\n<p>Hier ist ein Beispiel:<\/p>\n<pre><code class=\"language-js\">\/\/ Old bot\nfunction Robot() {\n\n   this.walk = function(numberOfSteps) {\n       \/\/ code to make the robot walk\n       console.log(\"walked \" + numberOfSteps + \" steps\")\n   }\n\n   this.sit = function() {\n       \/\/ code to make the robot sit\n       console.log(\"sit\")\n   }\n\n}\n\n\/\/ New bot that does not have the walk function anymore\n\/\/ but instead has functions to control each step independently\nfunction AdvancedRobot(botName) {\n   \/\/ the new bot has a name as well\n   this.name = botName\n\n   this.sit = function() {\n       \/\/ code to make the robot sit\n       console.log(\"sit\")\n   }\n\n   this.rightStepForward = function() {\n       \/\/ code to take 1 step from right leg forward\n       console.log(\"right step forward\")\n   }\n\n   this.leftStepForward = function () {\n       \/\/ code to take 1 step from left leg forward\n       console.log(\"left step forward\")\n   }\n}\n\nfunction RobotAdapter(botName) {\n   \/\/ No references to the old interfact since that is usually\n   \/\/ phased out of development\n   const robot = new AdvancedRobot(botName)\n\n   \/\/ The adapter defines the walk function by using the\n   \/\/ two step controls. You now have room to choose which leg to begin\/end with,\n   \/\/ and do something at each step.\n   this.walk = function(numberOfSteps) {\n       for (let i=0; i&lt;numberOfSteps; i++) {\n          \n           if (i % 2 === 0) {\n               robot.rightStepForward()\n           } else {\n               robot.leftStepForward()\n           }\n       }\n   }\n\n   this.sit = robot.sit\n\n}\n\nfunction run() {\n\n   let robot = new Robot()\n\n   robot.sit()\n   \/\/ Output: sit\n   robot.walk(5)\n   \/\/ Output: walked 5 steps\n\n   robot = new RobotAdapter(\"my bot\")\n\n   robot.sit()\n   \/\/ Output: sit\n   robot.walk(5)\n   \/\/ Output:\n   \/\/ right step forward\n   \/\/ left step forward\n   \/\/ right step forward\n   \/\/ left step forward\n   \/\/ right step forward\n\n}\n\nrun()<\/code><\/pre>\n<p>Das Hauptproblem bei diesem Entwurfsmuster ist, dass es die Komplexit\u00e4t deines Quellcodes erh\u00f6ht. Du musstest bereits zwei verschiedene Klassen pflegen, und jetzt kommt noch eine weitere Klasse hinzu &#8211; der Adapter.<\/p>\n<h4>7. Bridge<\/h4>\n<p>Als Erweiterung des Adapter-Musters bietet das Bridge-Muster sowohl der Klasse als auch dem Client getrennte Schnittstellen, so dass beide auch bei inkompatiblen nativen Schnittstellen funktionieren k\u00f6nnen.<\/p>\n<p>Es hilft bei der Entwicklung einer sehr lose gekoppelten Schnittstelle zwischen den beiden Objekttypen. Dies tr\u00e4gt auch dazu bei, die Erweiterbarkeit der Schnittstellen und ihrer Implementierungen zu verbessern, um maximale Flexibilit\u00e4t zu erreichen.<\/p>\n<p>Hier erf\u00e4hrst du, wie du sie nutzen kannst:<\/p>\n<pre><code class=\"language-js\">\/\/ The TV and speaker share the same interface\nfunction TV() {\n   this.increaseVolume = function() {\n       \/\/ logic to increase TV volume\n   }\n\n   this.decreaseVolume = function() {\n       \/\/ logic to decrease TV volume\n   }\n\n   this.mute = function() {\n       \/\/ logic to mute TV audio\n   }\n}\n\nfunction Speaker() {\n   this.increaseVolume = function() {\n       \/\/ logic to increase speaker volume\n   }\n\n   this.decreaseVolume = function() {\n       \/\/ logic to decrease speaker volume\n   }\n\n   this.mute() = function() {\n       \/\/ logic to mute speaker audio\n   }\n}\n\n\/\/ The two remotes make use of the same common interface\n\/\/ that supports volume up and volume down features\nfunction SimpleRemote(device) {\n   this.pressVolumeDownKey = function() {\n       device.decreaseVolume()\n   }\n\n   this.pressVolumeUpKey = function() {\n       device.increaseVolume()\n   }\n}\n\nfunction AdvancedRemote(device) {\n\n   this.pressVolumeDownKey = function() {\n       device.decreaseVolume()\n   }\n\n   this.pressVolumeUpKey = function() {\n       device.increaseVolume()\n   }\n\n   this.pressMuteKey = function() {\n       device.mute()\n   }\n}\n\nfunction run() {\n\n   let tv = new TV()\n   let speaker = new Speaker()\n\n   let tvSimpleRemote = new SimpleRemote(tv)\n   let tvAdvancedRemote = new AdvancedRemote(tv)\n\n   let speakerSimpleRemote = new SimpleRemote(speaker)\n   let speakerAdvancedRemote = new AdvancedRemote(speaker)\n\n   \/\/ The methods listed in pair below will have the same effect\n   \/\/ on their target devices\n   tvSimpleRemote.pressVolumeDownKey()\n   tvAdvancedRemote.pressVolumeDownKey()\n\n   tvSimpleRemote.pressVolumeUpKey()\n   tvAdvancedRemote.pressVolumeUpKey()\n\n   \/\/ The advanced remote has additional functionality\n   tvAdvancedRemote.pressMuteKey()\n\n   speakerSimpleRemote.pressVolumeDownKey()\n   speakerAdvancedRemote.pressVolumeDownKey()\n\n   speakerSimpleRemote.pressVolumeUpKey()\n   speakerAdvancedRemote.pressVolumeUpKey()\n\n   speakerAdvancedRemote.pressMuteKey()\n}<\/code><\/pre>\n<p>Wie du vielleicht schon vermutet hast, erh\u00f6ht das Bridge-Muster die Komplexit\u00e4t der Codebasis erheblich. Au\u00dferdem gibt es f\u00fcr die meisten Schnittstellen in der Praxis nur eine einzige Implementierung, so dass du nicht wirklich von der Wiederverwendbarkeit des Codes profitierst.<\/p>\n<h4>8. Composite<\/h4>\n<p>Das Composite Design Pattern hilft dir, \u00e4hnliche Objekte und Entit\u00e4ten einfach zu strukturieren und zu verwalten. Die Grundidee hinter dem Composite-Muster ist, dass die Objekte und ihre logischen Container durch eine einzige abstrakte Klasse dargestellt werden k\u00f6nnen (die Daten\/Methoden f\u00fcr das Objekt und Referenzen auf sich selbst f\u00fcr den Container speichern kann).<\/p>\n<p>Die Verwendung des Composite-Musters ist am sinnvollsten, wenn dein Datenmodell einer Baumstruktur \u00e4hnelt. Du solltest jedoch nicht versuchen, ein Datenmodell ohne Baumstruktur in ein baum\u00e4hnliches Datenmodell umzuwandeln, nur um das Composite-Muster zu verwenden, denn dadurch geht oft eine Menge Flexibilit\u00e4t verloren.<\/p>\n<p>Im folgenden Beispiel siehst du, wie du das Composite Design Pattern nutzen kannst, um ein Verpackungssystem f\u00fcr E-Commerce-Produkte zu erstellen, das auch den Gesamtbestellwert pro Paket berechnen kann:<\/p>\n<pre><code class=\"language-js\">\/\/ A product class, that acts as a Leaf node\nfunction Product(name, price) {\n   this.name = name\n   this.price = price\n\n   this.getTotalPrice = function() {\n       return this.price\n   }\n}\n\n\/\/ A box class, that acts as a parent\/child node\nfunction Box(name) {\n   this.contents = []\n   this.name = name\n\n   \/\/ Helper function to add an item to the box\n   this.add = function(content){\n       this.contents.push(content)\n   }\n\n   \/\/ Helper function to remove an item from the box\n   this.remove = function() {\n       var length = this.contents.length;\n       for (var i = 0; i &lt; length; i++) {\n           if (this.contents[i] === child) {\n               this.contents.splice(i, 1);\n               return;\n           }\n       }\n   }\n\n   \/\/ Helper function to get one item from the box\n   this.getContent = function(position) {\n       return this.contents[position]\n   }\n\n   \/\/ Helper function to get the total count of the items in the box\n   this.getTotalCount = function() {\n       return this.contents.length\n   }\n\n   \/\/ Helper function to calculate the total price of all items in the box\n   this.getTotalPrice = function() {\n       let totalPrice = 0;\n\n       for (let i=0; i &lt; this.getTotalCount(); i++){\n           totalPrice += this.getContent(i).getTotalPrice()\n       }\n\n       return totalPrice\n   }\n}\n\nfunction run() {\n\n   \/\/ Let's create some electronics\n   const mobilePhone = new Product(\"mobile phone,\" 1000)\n   const phoneCase = new Product(\"phone case,\" 30)\n   const screenProtector = new Product(\"screen protector,\" 20)\n\n   \/\/ and some stationery products\n   const pen = new Product(\"pen,\" 2)\n   const pencil = new Product(\"pencil,\" 0.5)\n   const eraser = new Product(\"eraser,\" 0.5)\n   const stickyNotes = new Product(\"sticky notes,\" 10)\n\n   \/\/ and put them in separate boxes\n   const electronicsBox = new Box(\"electronics\")\n   electronicsBox.add(mobilePhone)\n   electronicsBox.add(phoneCase)\n   electronicsBox.add(screenProtector)\n  \n   const stationeryBox = new Box(\"stationery\")\n   stationeryBox.add(pen)\n   stationeryBox.add(pencil)\n   stationeryBox.add(eraser)\n   stationeryBox.add(stickyNotes)\n\n   \/\/ and finally, put them into one big box for convenient shipping\n   const package = new Box('package')\n   package.add(electronicsBox)\n   package.add(stationeryBox)\n\n   \/\/ Here's an easy way to calculate the total order value\n   console.log(\"Total order price: USD \" + package.getTotalPrice())\n   \/\/ Output: USD 1063\n}\n\nrun()<\/code><\/pre>\n<p>Der gr\u00f6\u00dfte Nachteil bei der Verwendung des Composite-Musters ist, dass \u00c4nderungen an den Komponentenschnittstellen in der Zukunft sehr schwierig sein k\u00f6nnen. Die Entwicklung der Schnittstellen ist zeitaufw\u00e4ndig und m\u00fchsam, und die baumartige Struktur des Datenmodells kann es sehr schwierig machen, \u00c4nderungen nach Belieben vorzunehmen.<\/p>\n<h4>9. Decorator<\/h4>\n<p>Das Decorator-Muster hilft dir, neue Funktionen zu bestehenden Objekten hinzuzuf\u00fcgen, indem du sie einfach in ein neues Objekt verpackst. Das ist so \u00e4hnlich, wie wenn du einen bereits eingepackten Geschenkkarton beliebig oft mit neuem Geschenkpapier umwickeln k\u00f6nntest: Mit jeder Umh\u00fcllung kannst du so viele Funktionen hinzuf\u00fcgen, wie du m\u00f6chtest &#8211; die Flexibilit\u00e4t ist also gro\u00df.<\/p>\n<p>Aus technischer Sicht gibt es keine Vererbung, sodass du bei der Entwicklung der Gesch\u00e4ftslogik mehr Freiheit hast.<\/p>\n<p>Im folgenden Beispiel siehst du, wie das Decorator-Muster dabei hilft, einer Standardklasse <code>Customer<\/code> mehr Funktionen hinzuzuf\u00fcgen:<\/p>\n<pre><code class=\"language-js\">function Customer(name, age) {\n   this.name = name\n   this.age = age\n\n   this.printInfo = function() {\n       console.log(\"Customer:nName : \" + this.name + \" | Age: \" + this.age)\n   }\n}\n\nfunction DecoratedCustomer(customer, location) {\n   this.customer = customer\n   this.name = customer.name\n   this.age = customer.age\n   this.location = location\n\n   this.printInfo = function() {\n       console.log(\"Decorated Customer:nName: \" + this.name + \" | Age: \" + this.age + \" | Location: \" + this.location)\n   }\n}\n\nfunction run() {\n   let customer = new Customer(\"John,\" 25)\n   customer.printInfo()\n   \/\/ Output:\n   \/\/ Customer:\n   \/\/ Name : John | Age: 25\n\n   let decoratedCustomer = new DecoratedCustomer(customer, \"FL\")\n   decoratedCustomer.printInfo()\n   \/\/ Output:\n   \/\/ Customer:\n   \/\/ Name : John | Age: 25 | Location: FL\n}\n\nrun()<\/code><\/pre>\n<p>Zu den Nachteilen dieses Musters geh\u00f6rt die hohe Komplexit\u00e4t des Codes, da es kein Standardmuster f\u00fcr das Hinzuf\u00fcgen neuer Funktionen mithilfe von Decorators gibt. Es kann sein, dass du am Ende des Lebenszyklus deiner Softwareentwicklung eine Menge uneinheitlicher und\/oder \u00e4hnlicher Dekoratoren hast.<\/p>\n<p>Wenn du beim Design der Dekoratoren nicht aufpasst, kann es passieren, dass einige Dekoratoren logisch von anderen abh\u00e4ngig sind. Wenn dies nicht behoben wird, kann das Entfernen oder Umstrukturieren von Dekoratoren zu einem sp\u00e4teren Zeitpunkt die Stabilit\u00e4t deiner Anwendung beeintr\u00e4chtigen.<\/p>\n<h4>10. Facade<\/h4>\n<p>Wenn du die meisten realen Anwendungen entwickelst, wird die Gesch\u00e4ftslogik meist ziemlich komplex, wenn du fertig bist. Es kann vorkommen, dass du mehrere Objekte und Methoden hast, die an der Ausf\u00fchrung von Kernoperationen in deiner Anwendung beteiligt sind. Die \u00dcbersicht \u00fcber ihre Initialisierungen, Abh\u00e4ngigkeiten, die richtige Reihenfolge der Methodenausf\u00fchrung usw. zu behalten, kann ziemlich kompliziert und fehleranf\u00e4llig sein, wenn du es nicht richtig machst.<\/p>\n<p>Das Facade Design Pattern hilft dir, eine Abstraktion zwischen der Umgebung, die die oben genannten Vorg\u00e4nge aufruft, und den Objekten und Methoden zu schaffen, die an der Ausf\u00fchrung dieser Vorg\u00e4nge beteiligt sind. Diese Abstraktion enth\u00e4lt die Logik f\u00fcr die Initialisierung der Objekte, die Verfolgung ihrer Abh\u00e4ngigkeiten und andere wichtige Aktivit\u00e4ten. Die aufrufende Umgebung hat keine Informationen dar\u00fcber, wie eine Operation ausgef\u00fchrt wird. Du kannst die Logik frei aktualisieren, ohne den aufrufenden Client zu ver\u00e4ndern.<\/p>\n<p>So kannst du sie in einer Anwendung verwenden:<\/p>\n<pre><code class=\"language-js\">\/**\n* Let's say you're trying to build an online store. It will have multiple components and\n* complex business logic. In the example below, you will find a tiny segment of an online\n* store composed together using the Facade design pattern. The various manager and helper\n* classes are defined first of all.\n*\/\n\n\nfunction CartManager() {\n   this.getItems = function() {\n       \/\/ logic to return items\n       return []\n   }\n  \n   this.clearCart = function() {\n       \/\/ logic to clear cart\n   }\n}\n\nfunction InvoiceManager() {\n   this.createInvoice = function(items) {\n       \/\/ logic to create invoice\n       return {}\n   }\n\n   this.notifyCustomerOfFailure = function(invoice) {\n       \/\/ logic to notify customer\n   }\n\n   this.updateInvoicePaymentDetails = function(paymentResult) {\n       \/\/ logic to update invoice after payment attempt\n   }\n}\n\nfunction PaymentProcessor() {\n   this.processPayment = function(invoice) {\n       \/\/ logic to initiate and process payment\n       return {}\n   }\n}\n\nfunction WarehouseManager() {\n   this.prepareForShipping = function(items, invoice) {\n       \/\/ logic to prepare the items to be shipped\n   }\n}\n\n\/\/ This is where facade comes in. You create an additional interface on top of your\n\/\/ existing interfaces to define the business logic clearly. This interface exposes\n\/\/ very simple, high-level methods for the calling environment.\nfunction OnlineStore() {\n   this.name = \"Online Store\"\n  \n   this.placeOrder = function() {\n       let cartManager = new CartManager()\n       let items = cartManager.getItems()\n\n       let invoiceManager = new InvoiceManager()\n       let invoice = invoiceManager.createInvoice(items)\n      \n       let paymentResult = new PaymentProcessor().processPayment(invoice)\n       invoiceManager.updateInvoicePaymentDetails(paymentResult)\n\n       if (paymentResult.status === 'success') {\n           new WarehouseManager().prepareForShipping(items, invoice)\n           cartManager.clearCart()\n       } else {\n           invoiceManager.notifyCustomerOfFailure(invoice)\n       }\n      \n   }\n}\n\n\/\/ The calling environment is unaware of what goes on when somebody clicks a button to\n\/\/ place the order. You can easily change the underlying business logic without breaking\n\/\/ your calling environment.\nfunction run() {\n   let onlineStore = new OnlineStore()\n\n   onlineStore.placeOrder()\n}<\/code><\/pre>\n<p>Ein Nachteil des Facade Patterns ist, dass es eine zus\u00e4tzliche Abstraktionsebene zwischen deiner Gesch\u00e4ftslogik und dem Client einf\u00fcgt, was zus\u00e4tzliche Wartung erfordert. In den meisten F\u00e4llen erh\u00f6ht sich dadurch die Gesamtkomplexit\u00e4t der Codebasis.<\/p>\n<p>Au\u00dferdem wird die Klasse <code>Facade<\/code> zu einer zwingenden Abh\u00e4ngigkeit f\u00fcr das Funktionieren deiner App. Das bedeutet, dass sich Fehler in der Klasse <code>Facade<\/code> direkt auf das Funktionieren deiner App auswirken.<\/p>\n<h4>11. Flyweight<\/h4>\n<p>Das Flyweight-Muster hilft dir, Probleme mit Objekten mit sich wiederholenden Komponenten auf speichereffiziente Weise zu l\u00f6sen, indem es dir hilft, die gemeinsamen Komponenten deines Objektpools wiederzuverwenden. Dadurch wird der Speicher entlastet und die Ausf\u00fchrungszeit verk\u00fcrzt.<\/p>\n<p>Im folgenden Beispiel wird ein gro\u00dfer Satz mit Hilfe des Flyweight-Designmusters im Speicher abgelegt. Anstatt jedes einzelne Zeichen zu speichern, identifiziert das Programm die Menge der verschiedenen Zeichen, die zum Schreiben des Absatzes verwendet wurden, sowie deren Typen (Zahl oder Alphabet) und erstellt f\u00fcr jedes Zeichen wiederverwendbare Flyweights, die Angaben dar\u00fcber enthalten, welches Zeichen und welcher Typ gespeichert sind.<\/p>\n<p>Das Hauptarray speichert dann einfach eine Liste von Verweisen auf diese Fliegengewichte in der Reihenfolge, in der sie im Satz vorkommen, anstatt eine Instanz des Zeichenobjekts zu speichern, sobald es auftritt.<\/p>\n<p>Dadurch wird der Speicherbedarf des Satzes um die H\u00e4lfte reduziert. Bedenke, dass dies eine sehr grundlegende Erkl\u00e4rung daf\u00fcr ist, wie Textverarbeitungsprogramme Text speichern.<\/p>\n<pre><code class=\"language-js\">\/\/ A simple Character class that stores the value, type, and position of a character\nfunction Character(value, type, position) {\n   this.value = value\n   this.type = type\n   this.position = position\n}\n\n\/\/ A Flyweight class that stores character value and type combinations\nfunction CharacterFlyweight(value, type) {\n   this.value = value\n   this.type = type\n}\n\n\/\/ A factory to automatically create the flyweights that are not present in the list,\n\/\/ and also generate a count of the total flyweights in the list\nconst CharacterFlyweightFactory = (function () {\n   const flyweights = {}\n\n   return {\n       get: function (value, type) {\n           if (flyweights[value + type] === undefined)\n               flyweights[value + type] = new CharacterFlyweight(value, type)\n\n           return flyweights[value + type]\n       },\n       count: function () {\n           let count = 0;\n           for (var f in flyweights) count++;\n           return count;\n       }\n   }\n})()\n\n\/\/ An enhanced Character class that uses flyweights to store references\n\/\/ to recurring value and type combinations\nfunction CharacterWithFlyweight(value, type, position) {\n   this.flyweight = CharacterFlyweightFactory.get(value, type)\n   this.position = position\n}\n\n\/\/ A helper function to define the type of a character\n\/\/ It identifies numbers as N and everything as A (for alphabets)\nfunction getCharacterType(char) {\n   switch (char) {\n       case \"0\":\n       case \"1\":\n       case \"2\":\n       case \"3\":\n       case \"4\":\n       case \"5\":\n       case \"6\":\n       case \"7\":\n       case \"8\":\n       case \"9\": return \"N\"\n       default:\n           return \"A\"\n\n   }\n}\n\n\/\/ A list class to create an array of Characters from a given string\nfunction CharactersList(str) {\n   chars = []\n   for (let i = 0; i &lt; str.length; i++) {\n       const char = str[i]\n       chars.push(new Character(char, getCharacterType(char), i))\n   }\n\n   return chars\n}\n\n\/\/ A list class to create an array of CharacterWithFlyweights from a given string\nfunction CharactersWithFlyweightsList(str) {\n   chars = []\n   for (let i = 0; i  \" + charactersList.length)\n   \/\/ Output: Character count -&gt; 656\n\n   \/\/ The number of flyweights created is only 31, since only 31 characters are used to write the\n   \/\/ entire paragraph. This means that to store 656 characters, a total of\n   \/\/ (31 * 2 + 656 * 1 = 718) memory blocks are used instead of (656 * 3 = 1968) which would have\n   \/\/ used by the standard array.\n   \/\/ (We have assumed each variable to take up one memory block for simplicity. This\n   \/\/ may vary in real-life scenarios)\n   console.log(\"Flyweights created -&gt; \" + CharacterFlyweightFactory.count())\n   \/\/ Output: Flyweights created -&gt; 31\n\n}\n\nrun()<\/code><\/pre>\n<p>Wie du vielleicht schon gemerkt hast, macht das Flyweight-Muster dein Softwaredesign komplizierter, weil es nicht besonders intuitiv ist. Wenn es f\u00fcr deine Anwendung also nicht so wichtig ist, Speicherplatz zu sparen, kann die zus\u00e4tzliche Komplexit\u00e4t von Flyweight mehr schaden als n\u00fctzen.<\/p>\n<p>Au\u00dferdem tauschen Flyweights Speicher gegen Verarbeitungseffizienz. Wenn du also wenig CPU-Zyklen zur Verf\u00fcgung hast, ist Flyweight keine gute L\u00f6sung f\u00fcr dich.<\/p>\n<h4>12. Proxy<\/h4>\n<p>Mit dem Proxy-Muster kannst du ein Objekt durch ein anderes Objekt ersetzen. Mit anderen Worten: Proxy-Objekte k\u00f6nnen an die Stelle von Objekten treten, die sie eigentlich sind, und den Zugriff auf das Objekt kontrollieren. Diese Proxy-Objekte k\u00f6nnen verwendet werden, um bestimmte Aktionen auszuf\u00fchren, bevor oder nachdem eine Aufrufanforderung an das eigentliche Objekt weitergeleitet wird.<\/p>\n<p>Im folgenden Beispiel siehst du, wie der Zugriff auf eine Datenbankinstanz \u00fcber einen Proxy gesteuert wird, der einige grundlegende \u00dcberpr\u00fcfungen der Anfragen durchf\u00fchrt, bevor er sie durchl\u00e4sst:<\/p>\n<pre><code class=\"language-js\">function DatabaseHandler() {\n   const data = {}\n\n   this.set = function (key, val) {\n       data[key] = val;\n   }\n   this.get = function (key, val) {\n       return data[key]\n   }\n   this.remove = function (key) {\n       data[key] = null;\n   }\n\n\n}\n\nfunction DatabaseProxy(databaseInstance) {\n\n   this.set = function (key, val) {\n       if (key === \"\") {\n           console.log(\"Invalid input\")\n           return\n       }\n\n       if (val === undefined) {\n           console.log(\"Setting value to undefined not allowed!\")\n           return\n       }\n\n       databaseInstance.set(key, val)\n   }\n\n   this.get = function (key) {\n       if (databaseInstance.get(key) === null) {\n           console.log(\"Element deleted\")\n       }\n\n       if (databaseInstance.get(key) === undefined) {\n           console.log(\"Element not created\")\n       }\n\n       return databaseInstance.get(key)\n   }\n\n   this.remove = function (key) {\n       if (databaseInstance.get(key) === undefined) {\n           console.log(\"Element not added\")\n           return\n       }\n\n       if (databaseInstance.get(key) === null) {\n           console.log(\"Element removed already\")\n           return\n       }\n\n       return databaseInstance.remove(key)\n   }\n\n}\n\nfunction run() {\n   let databaseInstance = new DatabaseHandler()\n\n   databaseInstance.set(\"foo,\" \"bar\")\n   databaseInstance.set(\"foo,\" undefined)\n   console.log(\"#1: \" + databaseInstance.get(\"foo\"))\n   \/\/ #1: undefined\n\n   console.log(\"#2: \" + databaseInstance.get(\"baz\"))\n   \/\/ #2: undefined\n\n   databaseInstance.set(\",\" \"something\")\n\n   databaseInstance.remove(\"foo\")\n   console.log(\"#3: \" + databaseInstance.get(\"foo\"))\n   \/\/ #3: null\n\n   databaseInstance.remove(\"foo\")\n   databaseInstance.remove(\"baz\")\n\n   \/\/ Create a fresh database instance to try the same operations\n   \/\/ using the proxy\n   databaseInstance = new DatabaseHandler()\n   let proxy = new DatabaseProxy(databaseInstance)\n\n   proxy.set(\"foo,\" \"bar\")\n   proxy.set(\"foo,\" undefined)\n   \/\/ Proxy jumps in:\n   \/\/ Output: Setting value to undefined not allowed!\n\n   console.log(\"#1: \" + proxy.get(\"foo\"))\n   \/\/ Original value is retained:\n   \/\/ Output: #1: bar\n\n   console.log(\"#2: \" + proxy.get(\"baz\"))\n   \/\/ Proxy jumps in again\n   \/\/ Output:\n   \/\/ Element not created\n   \/\/ #2: undefined\n\n\n   proxy.set(\",\" \"something\")\n   \/\/ Proxy jumps in again\n   \/\/ Output: Invalid input\n\n   proxy.remove(\"foo\")\n\n   console.log(\"#3: \" + proxy.get(\"foo\"))\n   \/\/ Proxy jumps in again\n   \/\/ Output:\n   \/\/ Element deleted\n   \/\/ #3: null\n\n   proxy.remove(\"foo\")\n   \/\/ Proxy output: Element removed already\n   proxy.remove(\"baz\")\n   \/\/ Proxy output: Element not added\n\n}\n\nrun()<\/code><\/pre>\n<p>Dieses Entwurfsmuster wird in der Branche h\u00e4ufig verwendet und hilft dabei, Vorg\u00e4nge vor und nach der Ausf\u00fchrung einfach zu implementieren. Wie jedes andere Entwurfsmuster erh\u00f6ht es jedoch auch die Komplexit\u00e4t deiner Codebasis, daher solltest du es nicht verwenden, wenn du es nicht wirklich brauchst.<\/p>\n<p>Au\u00dferdem solltest du bedenken, dass ein zus\u00e4tzliches Objekt an den Aufrufen deines eigentlichen Objekts beteiligt ist, so dass es aufgrund der zus\u00e4tzlichen Verarbeitungsvorg\u00e4nge zu einer gewissen Latenz kommen kann. Wenn du die Leistung deines Hauptobjekts optimierst, musst du auch die Methoden deines Proxys auf Leistung optimieren.<\/p>\n<h3>Verhalten<\/h3>\n<p>Verhaltensmuster helfen dir, Probleme zu l\u00f6sen, bei denen es darum geht, wie Objekte miteinander interagieren. Dazu kann die gemeinsame Nutzung oder die \u00dcbergabe von Verantwortung\/Kontrolle zwischen Objekten geh\u00f6ren, um bestimmte Operationen durchzuf\u00fchren. Es kann auch darum gehen, Daten so effizient wie m\u00f6glich an mehrere Objekte weiterzugeben oder gemeinsam zu nutzen.<\/p>\n<h4>13. Chain of Responsibility<\/h4>\n<p>Das Chain of Responsibility Muster ist eines der einfachsten Verhaltensmuster. Es ist n\u00fctzlich, wenn du eine Logik f\u00fcr Operationen entwickelst, die von mehreren Handlern ausgef\u00fchrt werden k\u00f6nnen.<\/p>\n<p>\u00c4hnlich wie bei der Problemeskalation in Support-Teams wird die Kontrolle \u00fcber eine Kette von Handlern weitergegeben, und der Handler, der f\u00fcr die Aktion verantwortlich ist, schlie\u00dft die Operation ab. Dieses Entwurfsmuster wird h\u00e4ufig bei der Gestaltung von Benutzeroberfl\u00e4chen verwendet, wo mehrere Komponentenschichten ein Eingabeereignis des Benutzers verarbeiten k\u00f6nnen, z. B. eine Ber\u00fchrung oder ein Wischen.<\/p>\n<p>Unten siehst du ein Beispiel f\u00fcr eine Beschwerde-Eskalation, bei der das Chain of Responsibility-Muster verwendet wird. Die Beschwerde wird von den Bearbeitern je nach Schweregrad bearbeitet:<\/p>\n<pre><code class=\"language-js\">\/\/ Complaint class that stores title and severity of a complaint\n\/\/ Higher value of severity indicates a more severe complaint\nfunction Complaint (title, severity) {\n    this.title = title\n    this.severity = severity\n}\n\n\/\/ Base level handler that receives all complaints\nfunction Representative () {\n    \/\/ If this handler can not handle the complaint, it will be forwarded to the next level\n    this.nextLevel = new Management()\n\n    this.handleComplaint = function (complaint) {\n        if (complaint.severity === 0)\n            console.log(\"Representative resolved the following complaint: \" + complaint.title)\n        else\n            this.nextLevel.handleComplaint(complaint)\n    }\n}\n\n\/\/ Second level handler to handle complaints of severity 1\nfunction Management() {\n    \/\/ If this handler can not handle the complaint, it will be forwarded to the next level\n    this.nextLevel = new Leadership()\n\n    this.handleComplaint = function (complaint) {\n        if (complaint.severity === 1)\n            console.log(\"Management resolved the following complaint: \" + complaint.title)\n        else\n            this.nextLevel.handleComplaint(complaint)\n    }\n}\n\n\/\/ Highest level handler that handles all complaints unhandled so far\nfunction Leadership() {\n    this.handleComplaint = function (complaint) {\n        console.log(\"Leadership resolved the following complaint: \" + complaint.title)\n    }\n}\n\nfunction run() {\n    \/\/ Create an instance of the base level handler\n    let customerSupport = new Representative()\n\n    \/\/ Create multiple complaints of varying severity and pass them to the base handler\n\n    let complaint1 = new Complaint(\"Submit button doesn't work,\" 0)\n    customerSupport.handleComplaint(complaint1)\n    \/\/ Output: Representative resolved the following complaint: Submit button doesn't work\n\n    let complaint2 = new Complaint(\"Payment failed,\" 1)\n    customerSupport.handleComplaint(complaint2)\n    \/\/ Output: Management resolved the following complaint: Payment failed\n\n    let complaint3 = new Complaint(\"Employee misdemeanour,\" 2)\n    customerSupport.handleComplaint(complaint3)\n    \/\/ Output: Leadership resolved the following complaint: Employee misdemeanour\n}\n\nrun()<\/code><\/pre>\n<p>Der offensichtliche Nachteil dieses Musters ist, dass es linear ist, d.h. es kann zu einer gewissen Latenz bei der Bearbeitung eines Vorgangs kommen, wenn eine gro\u00dfe Anzahl von Bearbeitern miteinander verkettet ist.<\/p>\n<p>Die \u00dcbersicht \u00fcber alle Handler zu behalten, kann ein weiteres Problem sein, da es ab einer bestimmten Anzahl von Handlern ziemlich un\u00fcbersichtlich werden kann. Die Fehlersuche ist ein weiterer Albtraum, da jede Anfrage bei einem anderen Handler enden kann, was es schwierig macht, den <a href=\"https:\/\/kinsta.com\/de\/blog\/node-debug\/\">Logging- und Debugging-Prozess<\/a> zu standardisieren.<\/p>\n<h4>14. Iterator<\/h4>\n<p>Das Iterator-Muster ist recht einfach und wird in fast allen modernen objektorientierten Sprachen h\u00e4ufig verwendet. Wenn du eine Liste von Objekten durchgehen musst, die nicht alle vom gleichen Typ sind, k\u00f6nnen normale Iterationsmethoden, wie z. B. for-Schleifen, ziemlich un\u00fcbersichtlich werden &#8211; vor allem, wenn du darin auch Gesch\u00e4ftslogik schreibst.<\/p>\n<p>Das Iterator-Muster kann dir helfen, die Iterations- und Verarbeitungslogik f\u00fcr deine Listen von der Hauptgesch\u00e4ftslogik zu isolieren.<\/p>\n<p>Im Folgenden zeige ich dir, wie du es bei einer einfachen Liste mit mehreren Arten von Elementen einsetzen kannst:<\/p>\n<pre><code class=\"language-js\">\/\/ Iterator for a complex list with custom methods\nfunction Iterator(list) {\n   this.list = list\n   this.index = 0\n\n   \/\/ Fetch the current element\n   this.current = function() {\n       return this.list[this.index]\n   }\n\n   \/\/ Fetch the next element in the list\n   this.next = function() {\n       return this.list[this.index++]\n   }\n\n   \/\/ Check if there is another element in the list\n   this.hasNext = function() {\n       return this.index &lt; this.list.length\n   }\n\n   \/\/ Reset the index to point to the initial element\n   this.resetIndex = function() {\n       this.index = 0\n   }\n\n   \/\/ Run a forEach loop over the list\n   this.forEach = function(callback) {\n       for (let element = this.next(); this.index &lt;= this.list.length; element = this.next()) {\n           callback(element)\n       }\n   }\n}\n\nfunction run() {\n   \/\/ A complex list with elements of multiple data types\n   let list = [\"Lorem ipsum,\" 9, [\"lorem ipsum dolor,\" true], false]\n\n   \/\/ Create an instance of the iterator and pass it the list\n   let iterator = new Iterator(list)\n\n   \/\/ Log the first element\n   console.log(iterator.current())\n   \/\/ Output: Lorem ipsum\n\n   \/\/ Print all elements of the list using the iterator's methods\n   while (iterator.hasNext()) {\n       console.log(iterator.next())\n       \/**\n        * Output:\n        * Lorem ipsum\n        * 9\n        * [ 'lorem ipsum dolor', true ]\n        * false\n        *\/\n   }\n\n   \/\/ Reset the iterator's index to the first element\n   iterator.resetIndex()\n\n   \/\/ Use the custom iterator to pass an effect that will run for each element of the list\n   iterator.forEach(function (element) {\n       console.log(element)\n   })\n   \/**\n    * Output:\n    * Lorem ipsum\n    * 9\n    * [ 'lorem ipsum dolor', true ]\n    * false\n    *\/\n}\n\nrun()<\/code><\/pre>\n<p>Es versteht sich von selbst, dass dieses Muster f\u00fcr Listen ohne mehrere Elementtypen unn\u00f6tig komplex sein kann. Wenn eine Liste zu viele Arten von Elementen enth\u00e4lt, kann sie au\u00dferdem schwer zu verwalten sein.<\/p>\n<p>Entscheidend ist, dass du anhand deiner Liste und ihrer zuk\u00fcnftigen \u00c4nderungsm\u00f6glichkeiten feststellst, ob du wirklich einen Iterator brauchst. Au\u00dferdem ist das Iterator-Muster nur bei Listen n\u00fctzlich, und Listen k\u00f6nnen dich manchmal auf ihren linearen Zugriffsmodus beschr\u00e4nken. Andere Datenstrukturen k\u00f6nnen dir manchmal gr\u00f6\u00dfere Leistungsvorteile bieten.<\/p>\n<h4>15. Mediator<\/h4>\n<p>Bei der Entwicklung deiner Anwendung kann es vorkommen, dass du mit einer gro\u00dfen Anzahl verschiedener Objekte arbeiten musst, die verschiedene Arten von Gesch\u00e4ftslogik enthalten und oft voneinander abh\u00e4ngen. Der Umgang mit diesen Abh\u00e4ngigkeiten kann manchmal schwierig sein, da du den \u00dcberblick dar\u00fcber behalten musst, wie diese Objekte Daten und Kontrolle untereinander austauschen.<\/p>\n<p>Das Mediator Design Pattern soll dir helfen, dieses Problem zu l\u00f6sen, indem es die Interaktionslogik f\u00fcr diese Objekte in einem eigenen Objekt isoliert.<\/p>\n<p>Dieses separate Objekt wird als Mediator bezeichnet und ist daf\u00fcr verantwortlich, dass deine untergeordneten Klassen ihre Arbeit erledigen. Dein Client oder die aufrufende Umgebung interagiert ebenfalls mit dem Mediator und nicht mit den untergeordneten Klassen.<\/p>\n<p>Hier ist ein Beispiel f\u00fcr das Mediator-Designmuster in Aktion:<\/p>\n<pre><code class=\"language-js\">\/\/ Writer class that receives an assignment, writes it in 2 seconds, and marks it as finished\nfunction Writer(name, manager) {\n    \n    \/\/ Reference to the manager, writer's name, and a busy flag that the manager uses while assigning the article\n    this.manager = manager\n    this.name = name\n    this.busy = false\n\n    this.startWriting = function (assignment) {\n        console.log(this.name + \" started writing \"\" + assignment + \"\"\")\n        this.assignment = assignment\n        this.busy = true\n\n        \/\/ 2 s timer to replicate manual action\n        setTimeout(() =&gt; { this.finishWriting() }, 2000)\n    }\n\n    this.finishWriting = function () {\n        if (this.busy === true) {\n            console.log(this.name + \" finished writing \"\" + this.assignment + \"\"\")\n            this.busy = false\n            return this.manager.notifyWritingComplete(this.assignment)\n        } else {\n            console.log(this.name + \" is not writing any article\")\n        }\n    }\n}\n\n\/\/ Editor class that receives an assignment, edits it in 3 seconds, and marks it as finished\nfunction Editor(name, manager) {\n    \n    \/\/ Reference to the manager, writer's name, and a busy flag that the manager uses while assigning the article\n    this.manager = manager\n    this.name = name\n    this.busy = false\n\n    this.startEditing = function (assignment) {\n        console.log(this.name + \" started editing \"\" + assignment + \"\"\")\n        this.assignment = assignment\n        this.busy = true\n\n        \/\/ 3 s timer to replicate manual action\n        setTimeout(() =&gt; { this.finishEditing() }, 3000)\n    }\n\n    this.finishEditing = function () {\n        if (this.busy === true) {\n            console.log(this.name + \" finished editing \"\" + this.assignment + \"\"\")\n            this.manager.notifyEditingComplete(this.assignment)\n            this.busy = false\n        } else {\n            console.log(this.name + \" is not editing any article\")\n        }\n    }\n}\n\n\/\/ The mediator class\nfunction Manager() {\n    \/\/ Store arrays of workers\n    this.editors = []\n    this.writers = []\n\n    this.setEditors = function (editors) {\n        this.editors = editors\n    }\n    this.setWriters = function (writers) {\n        this.writers = writers\n    }\n\n    \/\/ Manager receives new assignments via this method\n    this.notifyNewAssignment = function (assignment) {\n        let availableWriter = this.writers.find(function (writer) {\n            return writer.busy === false\n        })\n        availableWriter.startWriting(assignment)\n        return availableWriter\n    }\n\n    \/\/ Writers call this method to notify they're done writing\n    this.notifyWritingComplete = function (assignment) {\n        let availableEditor = this.editors.find(function (editor) {\n            return editor.busy === false\n        })\n        availableEditor.startEditing(assignment)\n        return availableEditor\n    }\n\n    \/\/ Editors call this method to notify they're done editing\n    this.notifyEditingComplete = function (assignment) {\n        console.log(\"\"\" + assignment + \"\" is ready to publish\")\n    }\n\n}\n\nfunction run() {\n    \/\/ Create a manager\n    let manager = new Manager()\n\n    \/\/ Create workers\n    let editors = [\n        new Editor(\"Ed,\" manager),\n        new Editor(\"Phil,\" manager),\n    ]\n\n    let writers = [\n        new Writer(\"Michael,\" manager),\n        new Writer(\"Rick,\" manager),\n    ]\n\n    \/\/ Attach workers to manager\n    manager.setEditors(editors)\n    manager.setWriters(writers)\n\n    \/\/ Send two assignments to manager\n    manager.notifyNewAssignment(\"var vs let in JavaScript\")\n    manager.notifyNewAssignment(\"JS promises\")\n\n    \/**\n     * Output:\n     * Michael started writing \"var vs let in JavaScript\"\n     * Rick started writing \"JS promises\"\n     * \n     * After 2s, output:\n     * Michael finished writing \"var vs let in JavaScript\"\n     * Ed started editing \"var vs let in JavaScript\"\n     * Rick finished writing \"JS promises\"\n     * Phil started editing \"JS promises\"\n     *\n     * After 3s, output:\n     * Ed finished editing \"var vs let in JavaScript\"\n     * \"var vs let in JavaScript\" is ready to publish\n     * Phil finished editing \"JS promises\"\n     * \"JS promises\" is ready to publish\n     *\/\n\n}\n\nrun()<\/code><\/pre>\n<p>Der Mediator bietet deinem App-Design zwar Entkopplung und eine gro\u00dfe Flexibilit\u00e4t, aber letztendlich ist er eine weitere Klasse, die du pflegen musst. Bevor du einen Mediator schreibst, musst du pr\u00fcfen, ob dein Design wirklich von einem Mediator profitieren kann, damit du deine Codebasis nicht unn\u00f6tig komplex machst.<\/p>\n<p>Du musst auch bedenken, dass die Mediatorenklasse zwar keine direkte Gesch\u00e4ftslogik enth\u00e4lt, aber dennoch eine Menge Code, der f\u00fcr das Funktionieren deiner App wichtig ist und daher schnell ziemlich komplex werden kann.<\/p>\n<h4>16. Memento<\/h4>\n<p>Die Versionierung von Objekten ist ein weiteres h\u00e4ufiges Problem, mit dem du bei der Entwicklung von Apps konfrontiert wirst. Es gibt viele Anwendungsf\u00e4lle, in denen du die Historie eines Objekts aufrechterhalten, einfache Rollbacks unterst\u00fctzen und manchmal sogar die R\u00fcckg\u00e4ngigmachung dieser Rollbacks erm\u00f6glichen musst. Die Logik f\u00fcr solche Anwendungen zu schreiben, kann schwierig sein.<\/p>\n<p>Das Memento Design Pattern ist daf\u00fcr gedacht, dieses Problem einfach zu l\u00f6sen.<\/p>\n<p>Ein Memento ist ein Schnappschuss eines Objekts zu einem bestimmten Zeitpunkt. Das Memento-Entwurfsmuster nutzt diese Mementos, um Schnappsch\u00fcsse des Objekts zu erhalten, wenn es im Laufe der Zeit ver\u00e4ndert wird. Wenn du zu einer alten Version zur\u00fcckkehren musst, kannst du einfach das Memento f\u00fcr diese Version abrufen.<\/p>\n<p>Hier siehst du, wie du es in einer Textverarbeitungs-App implementieren kannst:<\/p>\n<pre><code class=\"language-js\">\/\/ The memento class that can hold one snapshot of the Originator class - document\nfunction Text(contents) {\n    \/\/ Contents of the document\n    this.contents = contents\n\n    \/\/ Accessor function for contents\n    this.getContents = function () {\n        return this.contents\n    }\n\n    \/\/ Helper function to calculate word count for the current document\n    this.getWordCount = function () {\n        return this.contents.length\n    }\n}\n\n\/\/ The originator class that holds the latest version of the document\nfunction Document(contents) {\n    \/\/ Holder for the memento, i.e., the text of the document\n    this.text = new Text(contents)\n\n    \/\/ Function to save new contents as a memento\n    this.save = function (contents) {\n        this.text = new Text(contents)\n        return this.text\n    }\n\n    \/\/ Function to revert to an older version of the text using a memento\n    this.restore = function (text) {\n        this.text = new Text(text.getContents())\n    }\n\n    \/\/ Helper function to get the current memento\n    this.getText = function () {\n        return this.text\n    }\n\n    \/\/ Helper function to get the word count of the current document\n    this.getWordCount = function () {\n        return this.text.getWordCount()\n    }\n}\n\n\/\/ The caretaker class that providers helper functions to modify the document\nfunction DocumentManager(document) {\n    \/\/ Holder for the originator, i.e., the document\n    this.document = document\n\n    \/\/ Array to maintain a list of mementos\n    this.history = []\n\n    \/\/ Add the initial state of the document as the first version of the document\n    this.history.push(document.getText())\n\n    \/\/ Helper function to get the current contents of the documents\n    this.getContents = function () {\n        return this.document.getText().getContents()\n    }\n\n    \/\/ Helper function to get the total number of versions available for the document\n    this.getVersionCount = function () {\n        return this.history.length\n    }\n\n    \/\/ Helper function to get the complete history of the document\n    this.getHistory = function () {\n        return this.history.map(function (element) {\n            return element.getContents()\n        })\n\n    }\n\n    \/\/ Function to overwrite the contents of the document\n    this.overwrite = function (contents) {\n        let newVersion = this.document.save(contents)\n        this.history.push(newVersion)\n    }\n\n    \/\/ Function to append new content to the existing contents of the document\n    this.append = function (contents) {\n        let currentVersion = this.history[this.history.length - 1]\n        let newVersion\n        if (currentVersion === undefined)\n            newVersion = this.document.save(contents)\n        else\n            newVersion = this.document.save(currentVersion.getContents() + contents)\n        this.history.push(newVersion)\n    }\n\n    \/\/ Function to delete all the contents of the document\n    this.delete = function () {\n        this.history.push(this.document.save(\"\"))\n    }\n\n    \/\/ Function to get a particular version of the document\n    this.getVersion = function (versionNumber) {\n        return this.history[versionNumber - 1]\n    }\n\n    \/\/ Function to undo the last change\n    this.undo = function () {\n        let previousVersion = this.history[this.history.length - 2]\n        this.document.restore(previousVersion)\n        this.history.push(previousVersion)\n    }\n\n    \/\/ Function to revert the document to a previous version\n    this.revertToVersion = function (version) {\n        let previousVersion = this.history[version - 1]\n        this.document.restore(previousVersion)\n        this.history.push(previousVersion)\n    }\n\n    \/\/ Helper function to get the total word count of the document\n    this.getWordCount = function () {\n        return this.document.getWordCount()\n    }\n\n}\n\nfunction run() {\n    \/\/ Create a document\n    let blogPost = new Document(\"\")\n\n    \/\/ Create a caretaker for the document\n    let blogPostManager = new DocumentManager(blogPost)\n\n    \/\/ Change #1: Add some text\n    blogPostManager.append(\"Hello World!\")\n    console.log(blogPostManager.getContents())\n    \/\/ Output: Hello World!\n\n    \/\/ Change #2: Add some more text\n    blogPostManager.append(\" This is the second entry in the document\")\n    console.log(blogPostManager.getContents())\n    \/\/ Output: Hello World! This is the second entry in the document\n\n    \/\/ Change #3: Overwrite the document with some new text\n    blogPostManager.overwrite(\"This entry overwrites everything in the document\")\n    console.log(blogPostManager.getContents())\n    \/\/ Output: This entry overwrites everything in the document\n\n    \/\/ Change #4: Delete the contents of the document\n    blogPostManager.delete()\n    console.log(blogPostManager.getContents())\n    \/\/ Empty output\n\n    \/\/ Get an old version of the document\n    console.log(blogPostManager.getVersion(2).getContents())\n    \/\/ Output: Hello World!\n\n    \/\/ Change #5: Go back to an old version of the document\n    blogPostManager.revertToVersion(3)\n    console.log(blogPostManager.getContents())\n    \/\/ Output: Hello World! This is the second entry in the document\n\n    \/\/ Get the word count of the current document\n    console.log(blogPostManager.getWordCount())\n    \/\/ Output: 53\n\n    \/\/ Change #6: Undo the last change\n    blogPostManager.undo()\n    console.log(blogPostManager.getContents())\n    \/\/ Empty output\n\n    \/\/ Get the total number of versions for the document\n    console.log(blogPostManager.getVersionCount())\n    \/\/ Output: 7\n\n    \/\/ Get the complete history of the document\n    console.log(blogPostManager.getHistory())\n    \/**\n     * Output:\n     * [\n     *   '',\n     *   'Hello World!',\n     *   'Hello World! This is the second entry in the document',\n     *   'This entry overwrites everything in the document',\n     *   '',\n     *   'Hello World! This is the second entry in the document',\n     *   ''\n     * ]\n     *\/\n}\n\nrun()<\/code><\/pre>\n<p>Das Memento-Entwurfsmuster ist zwar eine gro\u00dfartige L\u00f6sung, um die Historie eines Objekts zu verwalten, aber es kann sehr ressourcenintensiv werden. Da jedes Memento fast eine Kopie des Objekts ist, kann es den Speicher deiner App sehr schnell aufbl\u00e4hen, wenn es nicht in Ma\u00dfen verwendet wird.<\/p>\n<p>Bei einer gro\u00dfen Anzahl von Objekten kann auch die Verwaltung ihres Lebenszyklus eine ziemlich m\u00fchsame Aufgabe sein. Dar\u00fcber hinaus sind die Klassen <code>Originator<\/code> und <code>Caretaker<\/code> in der Regel sehr eng miteinander verbunden, was die Komplexit\u00e4t deiner Codebasis noch erh\u00f6ht.<\/p>\n<h4>17. Observer<\/h4>\n<p>Das Observer-Muster bietet eine alternative L\u00f6sung f\u00fcr das Problem der Interaktion zwischen mehreren Objekten (wie es bereits beim Mediator-Muster der Fall war).<\/p>\n<p>Anstatt jedes Objekt \u00fcber einen bestimmten Mediator miteinander kommunizieren zu lassen, erlaubt das Observer-Muster, dass sich die Objekte gegenseitig beobachten. Die Objekte senden Ereignisse aus, wenn sie versuchen, Daten oder Steuerungsinformationen zu \u00fcbermitteln. Andere Objekte, die auf diese Ereignisse &#8222;h\u00f6ren&#8220;, k\u00f6nnen sie dann empfangen und auf der Grundlage ihres Inhalts interagieren.<\/p>\n<p>Hier ist eine einfache Demonstration des Versendens von Newslettern an mehrere Personen mithilfe des Observer-Musters:<\/p>\n<pre><code class=\"language-js\">\/\/ The newsletter class that can send out posts to its subscribers\nfunction Newsletter() {\n   \/\/ Maintain a list of subscribers\n   this.subscribers = []\n\n   \/\/ Subscribe a reader by adding them to the subscribers' list\n   this.subscribe = function(subscriber) {\n       this.subscribers.push(subscriber)\n   }\n\n   \/\/ Unsubscribe a reader by removing them from the subscribers' list\n   this.unsubscribe = function(subscriber) {\n       this.subscribers = this.subscribers.filter(\n           function (element) {\n               if (element !== subscriber) return element\n           }\n       )\n   }\n\n   \/\/ Publish a post by calling the receive function of all subscribers\n   this.publish = function(post) {\n       this.subscribers.forEach(function(element) {\n           element.receiveNewsletter(post)\n       })\n   }\n}\n\n\/\/ The reader class that can subscribe to and receive updates from newsletters\nfunction Reader(name) {\n   this.name = name\n\n   this.receiveNewsletter = function(post) {\n       console.log(\"Newsletter received by \" + name + \"!: \" + post)\n   }\n\n}\n\nfunction run() {\n   \/\/ Create two readers\n   let rick = new Reader(\"ed\")\n   let morty = new Reader(\"morty\")\n\n   \/\/ Create your newsletter\n   let newsletter = new Newsletter()\n\n   \/\/ Subscribe a reader to the newsletter\n   newsletter.subscribe(rick)\n\n   \/\/ Publish the first post\n   newsletter.publish(\"This is the first of the many posts in this newsletter\")\n   \/**\n    * Output:\n    * Newsletter received by ed!: This is the first of the many posts in this newsletter\n    *\/\n\n   \/\/ Subscribe another reader to the newsletter\n   newsletter.subscribe(morty)\n\n   \/\/ Publish the second post\n   newsletter.publish(\"This is the second of the many posts in this newsletter\")\n   \/**\n    * Output:\n    * Newsletter received by ed!: This is the second of the many posts in this newsletter\n    * Newsletter received by morty!: This is the second of the many posts in this newsletter\n    *\/\n\n   \/\/ Unsubscribe the first reader\n   newsletter.unsubscribe(rick)\n\n   \/\/ Publish the third post\n   newsletter.publish(\"This is the third of the many posts in this newsletter\")\n   \/**\n    * Output:\n    * Newsletter received by morty!: This is the third of the many posts in this newsletter\n    *\/\n\n}\n\nrun()<\/code><\/pre>\n<p>Das Observer-Muster ist zwar eine elegante Methode, um Kontrolle und Daten weiterzugeben, aber es eignet sich besser f\u00fcr Situationen, in denen eine gro\u00dfe Anzahl von Sendern und Empf\u00e4ngern \u00fcber eine begrenzte Anzahl von Verbindungen miteinander interagieren. Wenn die Objekte alle eine Eins-zu-Eins-Verbindung herstellen w\u00fcrden, w\u00fcrdest du den Vorteil verlieren, den du durch das Ver\u00f6ffentlichen und Abonnieren von Ereignissen erh\u00e4ltst, da es immer nur einen Abonnenten f\u00fcr jeden Verleger gibt (w\u00e4hrend eine direkte Kommunikation zwischen ihnen besser w\u00e4re).<\/p>\n<p>Au\u00dferdem kann das Observer-Designmuster zu Leistungsproblemen f\u00fchren, wenn die Abonnement-Ereignisse nicht richtig behandelt werden. Wenn ein Objekt weiterhin ein anderes Objekt abonniert, auch wenn es das nicht muss, kommt es <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lapsed_listener_problem\">nicht f\u00fcr die Garbage Collection in Frage<\/a> und erh\u00f6ht den Speicherverbrauch der App.<\/p>\n<h4>18. State<\/h4>\n<p>Das State Design Pattern ist eines der am h\u00e4ufigsten verwendeten Design Patterns in der Softwareentwicklungsbranche. Beliebte <a href=\"https:\/\/kinsta.com\/de\/blog\/javascript-bibliotheken\/\">JavaScript-Frameworks<\/a> wie <a href=\"https:\/\/reactjs.org\/docs\/state-and-lifecycle.html\">React<\/a> und <a href=\"https:\/\/medium.com\/olricdigital\/introduction-to-state-management-in-angular-v2-ef6f5144bade\">Angular<\/a> nutzen das State-Pattern, um Daten und das Verhalten der App auf Basis dieser Daten zu verwalten.<\/p>\n<p>Vereinfacht gesagt, ist das State Design Pattern hilfreich, wenn du definitive Zust\u00e4nde einer Entit\u00e4t (z. B. einer Komponente, einer Seite, einer App oder einer Maschine) definieren kannst und die Entit\u00e4t eine vordefinierte Reaktion auf die Zustands\u00e4nderung hat.<\/p>\n<p>Nehmen wir an, du versuchst, einen Kreditantragsprozess zu erstellen. Jeder Schritt im Antragsprozess kann als ein Zustand definiert werden.<\/p>\n<p>W\u00e4hrend der Kunde in der Regel eine kleine Liste mit vereinfachten Zust\u00e4nden seines Antrags sieht (ausstehend, in Pr\u00fcfung, angenommen und abgelehnt), k\u00f6nnen intern noch weitere Schritte hinzukommen. Bei jedem dieser Schritte wird der Antrag einer bestimmten Person zugewiesen und kann einzigartige Anforderungen haben.<\/p>\n<p>Das System ist so konzipiert, dass am Ende der Bearbeitung in einem Status der Status auf den n\u00e4chsten in der Reihe aktualisiert wird und der n\u00e4chste relevante Satz von Schritten gestartet wird.<\/p>\n<p>Hier erf\u00e4hrst du, wie du ein Aufgabenverwaltungssystem mit dem State Design Pattern aufbauen kannst:<\/p>\n<pre><code class=\"language-js\">\/\/ Create titles for all states of a task\nconst STATE_TODO = \"TODO\"\nconst STATE_IN_PROGRESS = \"IN_PROGRESS\"\nconst STATE_READY_FOR_REVIEW = \"READY_FOR_REVIEW\"\nconst STATE_DONE = \"DONE\"\n\n\/\/ Create the task class with a title, assignee, and duration of the task\nfunction Task(title, assignee) {\n    this.title = title\n    this.assignee = assignee\n\n    \/\/ Helper function to update the assignee of the task\n    this.setAssignee = function (assignee) {\n        this.assignee = assignee\n    }\n\n    \/\/ Function to update the state of the task\n    this.updateState = function (state) {\n\n        switch (state) {\n            case STATE_TODO:\n                this.state = new TODO(this)\n                break\n            case STATE_IN_PROGRESS:\n                this.state = new IN_PROGRESS(this)\n                break\n            case STATE_READY_FOR_REVIEW:\n                this.state = new READY_FOR_REVIEW(this)\n                break\n            case STATE_DONE:\n                this.state = new DONE(this)\n                break\n            default:\n                return\n        }\n        \/\/ Invoke the callback function for the new state after it is set\n        this.state.onStateSet()\n    }\n\n    \/\/ Set the initial state of the task as TODO\n    this.updateState(STATE_TODO)\n}\n\n\/\/ TODO state\nfunction TODO(task) {\n\n    this.onStateSet = function () {\n        console.log(task.assignee + \" notified about new task \"\" + task.title + \"\"\")\n    }\n}\n\n\/\/ IN_PROGRESS state\nfunction IN_PROGRESS(task) {\n\n    this.onStateSet = function () {\n        console.log(task.assignee + \" started working on the task \"\" + task.title + \"\"\")\n    }\n}\n\n\/\/ READY_FOR_REVIEW state that updates the assignee of the task to be the manager of the developer\n\/\/ for the review\nfunction READY_FOR_REVIEW(task) {\n    this.getAssignee = function () {\n        return \"Manager 1\"\n    }\n\n    this.onStateSet = function () {\n        task.setAssignee(this.getAssignee())\n        console.log(task.assignee + \" notified about completed task \"\" + task.title + \"\"\")\n    }\n}\n\n\/\/ DONE state that removes the assignee of the task since it is now completed\nfunction DONE(task) {\n    this.getAssignee = function () {\n        return \"\"\n    }\n\n    this.onStateSet = function () {\n        task.setAssignee(this.getAssignee())\n        console.log(\"Task \"\" + task.title + \"\" completed\")\n    }\n}\n\nfunction run() {\n    \/\/ Create a task\n    let task1 = new Task(\"Create a login page,\" \"Developer 1\")\n    \/\/ Output: Developer 1 notified about new task \"Create a login page\"\n\n    \/\/ Set it to IN_PROGRESS\n    task1.updateState(STATE_IN_PROGRESS)\n    \/\/ Output: Developer 1 started working on the task \"Create a login page\"\n\n    \/\/ Create another task\n    let task2 = new Task(\"Create an auth server,\" \"Developer 2\")\n    \/\/ Output: Developer 2 notified about new task \"Create an auth server\"\n\n\n    \/\/ Set it to IN_PROGRESS as well\n    task2.updateState(STATE_IN_PROGRESS)\n    \/\/ Output: Developer 2 started working on the task \"Create an auth server\"\n\n    \/\/ Update the states of the tasks until they are done\n    task2.updateState(STATE_READY_FOR_REVIEW)\n    \/\/ Output: Manager 1 notified about completed task \"Create an auth server\"\n    task1.updateState(STATE_READY_FOR_REVIEW)\n    \/\/ Output: Manager 1 notified about completed task \"Create a login page\"\n\n\n    task1.updateState(STATE_DONE)\n    \/\/ Output: Task \"Create a login page\" completed\n    task2.updateState(STATE_DONE)\n    \/\/ Output: Task \"Create an auth server\" completed\n\n}\n\nrun()<\/code><\/pre>\n<p>Das State-Pattern eignet sich zwar hervorragend, um die einzelnen Schritte eines Prozesses voneinander zu trennen, aber bei gro\u00dfen Anwendungen mit mehreren Zust\u00e4nden kann es extrem schwierig werden, es zu pflegen.<\/p>\n<p>Au\u00dferdem musst du mehr Code schreiben und pflegen, wenn dein Prozessdesign mehr als nur eine lineare Bewegung durch alle Zust\u00e4nde zul\u00e4sst, da jeder Zustands\u00fcbergang separat behandelt werden muss.<\/p>\n<h4>19. Strategy<\/h4>\n<p>Das Strategy-Pattern, auch bekannt als Policy-Pattern, soll dir dabei helfen, Klassen zu kapseln und frei auszutauschen, indem eine gemeinsame Schnittstelle verwendet wird. Dadurch wird eine lose Kopplung zwischen dem Client und den Klassen aufrechterhalten und du kannst so viele Implementierungen hinzuf\u00fcgen, wie du m\u00f6chtest.<\/p>\n<p>Das Strategy-Pattern ist daf\u00fcr bekannt, dass es in Situationen, in denen derselbe Vorgang mit verschiedenen Methoden\/Algorithmen ausgef\u00fchrt werden muss oder in denen umfangreiche Schaltbl\u00f6cke durch menschenfreundlicheren Code ersetzt werden m\u00fcssen, eine gro\u00dfe Hilfe ist.<\/p>\n<p>Hier ist ein Beispiel f\u00fcr das Strategy-Muster:<\/p>\n<pre><code class=\"language-js\">\/\/ The strategy class that can encapsulate all hosting providers\nfunction HostingProvider() {\n   \/\/ store the provider\n   this.provider = \"\"\n\n   \/\/ set the provider\n   this.setProvider = function(provider) {\n       this.provider = provider\n   }\n\n   \/\/ set the website configuration for which each hosting provider would calculate costs\n   this.setConfiguration = function(configuration) {\n       this.configuration = configuration\n   }\n\n   \/\/ the generic estimate method that calls the provider's unique methods to calculate the costs\n   this.estimateMonthlyCost = function() {\n       return this.provider.estimateMonthlyCost(this.configuration)\n   }\n}\n\n\/\/ Foo Hosting charges for each second and KB of hosting usage\nfunction FooHosting (){\n   this.name = \"FooHosting\"\n   this.rate = 0.0000027\n\n   this.estimateMonthlyCost = function(configuration){\n       return configuration.duration * configuration.workloadSize * this.rate\n   }\n}\n\n\/\/ Bar Hosting charges per minute instead of seconds\nfunction BarHosting (){\n   this.name = \"BarHosting\"\n   this.rate = 0.00018\n\n   this.estimateMonthlyCost = function(configuration){\n       return configuration.duration \/ 60 * configuration.workloadSize * this.rate\n   }\n}\n\n\/\/ Baz Hosting assumes the average workload to be of 10 MB in size\nfunction BazHosting (){\n   this.name = \"BazHosting\"\n   this.rate = 0.032\n\n   this.estimateMonthlyCost = function(configuration){\n       return configuration.duration * this.rate\n   }\n}\n\nfunction run() {\n\n   \/\/ Create a website configuration for a website that is up for 24 hours and takes 10 MB of hosting space\n   let workloadConfiguration = {\n       duration: 84700,\n       workloadSize: 10240\n   }\n\n   \/\/ Create the hosting provider instances\n   let fooHosting = new FooHosting()\n   let barHosting = new BarHosting()\n   let bazHosting = new BazHosting()\n\n   \/\/ Create the instance of the strategy class\n   let hostingProvider = new HostingProvider()\n\n   \/\/ Set the configuration against which the rates have to be calculated\n   hostingProvider.setConfiguration(workloadConfiguration)\n\n   \/\/ Set each provider one by one and print the rates\n   hostingProvider.setProvider(fooHosting)\n   console.log(\"FooHosting cost: \" + hostingProvider.estimateMonthlyCost())\n   \/\/ Output: FooHosting cost: 2341.7856\n\n   hostingProvider.setProvider(barHosting)\n   console.log(\"BarHosting cost: \" + hostingProvider.estimateMonthlyCost())\n   \/\/ Output: BarHosting cost: 2601.9840\n\n   hostingProvider.setProvider(bazHosting)\n   console.log(\"BarHosting cost: \" + hostingProvider.estimateMonthlyCost())\n   \/\/ Output: BarHosting cost: 2710.4000\n\n}\n\nrun()<\/code><\/pre>\n<p>Das Strategy-Muster eignet sich hervorragend, wenn es darum geht, neue Variationen einer Entit\u00e4t einzuf\u00fchren, ohne die Clients stark zu ver\u00e4ndern. Es kann aber zu viel sein, wenn du nur eine Handvoll Variationen implementieren musst.<\/p>\n<p>Au\u00dferdem werden durch die Kapselung feinere Details \u00fcber die interne Logik der einzelnen Varianten entfernt, so dass dein Kunde nicht wei\u00df, wie sich eine Variante verhalten wird.<\/p>\n<h4>20. Visitor<\/h4>\n<p>Das Visitor-Muster soll dir helfen, deinen Code erweiterbar zu machen.<\/p>\n<p>Die Idee ist, eine Methode in der Klasse bereitzustellen, die es Objekten anderer Klassen erm\u00f6glicht, auf einfache Weise \u00c4nderungen an Objekten der aktuellen Klasse vorzunehmen. Die anderen Objekte <em>besuchen<\/em> das aktuelle Objekt (auch Platzobjekt genannt), oder die aktuelle Klasse <em>akzeptiert <\/em>die Besucherobjekte, und das Platzobjekt behandelt den Besuch jedes externen Objekts entsprechend.<\/p>\n<p>So kannst du es verwenden:<\/p>\n<pre><code class=\"language-js\">\/\/ Visitor class that defines the methods to be called when visiting each place\nfunction Reader(name, cash) {\n    this.name = name\n    this.cash = cash\n\n    \/\/ The visit methods can access the place object and invoke available functions\n    this.visitBookstore = function(bookstore) {\n        console.log(this.name + \" visited the bookstore and bought a book\")\n        bookstore.purchaseBook(this)\n    }\n\n    this.visitLibrary = function() {\n        console.log(this.name + \" visited the library and read a book\")\n    }\n\n    \/\/ Helper function to demonstrate a transaction\n    this.pay = function(amount) {\n        this.cash -= amount\n    }\n}\n\n\/\/ Place class for a library\nfunction Library () {\n    this.accept = function(reader) {\n        reader.visitLibrary()\n    }\n}\n\n\/\/ Place class for a bookstore that allows purchasing book\nfunction Bookstore () {\n    this.accept = function(reader) {\n        reader.visitBookstore(this)\n    }\n\n    this.purchaseBook = function (visitor) {\n        console.log(visitor.name + \" bought a book\")\n        visitor.pay(8)\n    }\n}\n\n\nfunction run() {\n    \/\/ Create a reader (the visitor)\n    let reader = new Reader(\"Rick,\" 30)\n\n    \/\/ Create the places\n    let booksInc = new Bookstore()\n    let publicLibrary = new Library()\n\n    \/\/ The reader visits the library\n    publicLibrary.accept(reader)\n    \/\/ Output: Rick visited the library and read a book\n    console.log(reader.name + \" has $\" + reader.cash)\n    \/\/ Output: Rick has $30\n\n    \/\/ The reader visits the bookstore\n    booksInc.accept(reader)\n    \/\/ Output: Rick visited the bookstore and bought a book\n    console.log(reader.name + \" has $\" + reader.cash)\n    \/\/ Output: Rick has $22\n}\n\nrun()<\/code><\/pre>\n<p>Der einzige Nachteil dieses Designs ist, dass jede Besucherklasse aktualisiert werden muss, wenn ein neuer Ort hinzugef\u00fcgt oder ge\u00e4ndert wird. In F\u00e4llen, in denen mehrere Besucher- und Ortsobjekte zusammen existieren, kann dies schwierig zu pflegen sein.<\/p>\n<p>Abgesehen davon eignet sich die Methode hervorragend, um die Funktionalit\u00e4t von Klassen dynamisch zu erweitern.<\/p>\n<h2>Best Practices f\u00fcr die Umsetzung von Entwurfsmuster<\/h2>\n<p>Nachdem du nun die g\u00e4ngigsten Design Patterns in JavaScript kennengelernt hast, findest du hier einige Tipps, die du bei ihrer Umsetzung beachten solltest.<\/p>\n<h3>Achte besonders darauf, ob ein Muster zur L\u00f6sung passt<\/h3>\n<p>Diesen Tipp solltest du beherzigen, bevor du ein Entwurfsmuster in deinen Quellcode einbaust. Auch wenn es so aussieht, als w\u00e4re ein Entwurfsmuster das Ende all deiner Sorgen, nimm dir einen Moment Zeit, um kritisch zu analysieren, ob das auch stimmt.<\/p>\n<p>Es gibt viele Muster, die das gleiche Problem l\u00f6sen, aber unterschiedliche Ans\u00e4tze verfolgen und unterschiedliche Konsequenzen haben. Deine Kriterien f\u00fcr die Auswahl eines Entwurfsmusters sollten also nicht nur sein, ob es dein Problem l\u00f6st oder nicht &#8211; sie sollten auch sein, wie gut es dein Problem l\u00f6st und ob es ein anderes Muster gibt, das eine effizientere L\u00f6sung darstellt.<\/p>\n<h3>Verstehe die Kosten f\u00fcr die Implementierung eines Musters, bevor du anf\u00e4ngst<\/h3>\n<p>Auch wenn Entwurfsmuster die beste L\u00f6sung f\u00fcr alle <a href=\"https:\/\/kinsta.com\/de\/blog\/fehlern-in-javascript\/\">technischen Probleme<\/a> zu sein scheinen, solltest du sie nicht sofort in deinen Quellcode implementieren.<\/p>\n<p>Wenn du die Folgen der Implementierung einer L\u00f6sung absch\u00e4tzt, musst du auch deine eigene Situation ber\u00fccksichtigen. Hast du ein gro\u00dfes Team von Softwareentwicklern, die Design Patterns gut verstehen und pflegen k\u00f6nnen? Oder bist du ein Gr\u00fcnder in der Anfangsphase mit einem kleinen Entwicklungsteam, das schnell eine MVP-Version deines Produkts herausbringen will? Wenn du die letzte Frage mit Ja beantwortest, sind Design Patterns vielleicht nicht die optimale Entwicklungsmethode f\u00fcr dich.<\/p>\n<p>Design Patterns f\u00fchren nicht zu einer hohen Wiederverwendung von Code, es sei denn, sie werden bereits in einer sehr fr\u00fchen Phase des App-Designs geplant. Die wahllose Verwendung von Entwurfsmustern in verschiedenen Phasen kann zu einer unn\u00f6tig komplexen App-Architektur f\u00fchren, f\u00fcr deren Vereinfachung du Wochen brauchen w\u00fcrdest.<\/p>\n<p>Die Effektivit\u00e4t eines Entwurfsmusters l\u00e4sst sich nicht durch irgendwelche Tests beurteilen. Nur die <a href=\"https:\/\/kinsta.com\/de\/blog\/code-review-tools\/\">Erfahrung deines Teams und die Selbstbeobachtung<\/a> werden dir zeigen, ob sie funktionieren. Nur wenn du die Zeit und die Ressourcen hast, um diese Aspekte zu ber\u00fccksichtigen, werden Design Patterns deine Probleme wirklich l\u00f6sen.<\/p>\n<h3>Nicht jede L\u00f6sung in ein Muster verwandeln<\/h3>\n<p>Eine weitere Faustregel, die du beachten solltest, ist, nicht zu versuchen, jedes kleine Problem-L\u00f6sungs-Paar in ein Entwurfsmuster zu verwandeln und es \u00fcberall dort einzusetzen, wo du Platz daf\u00fcr siehst.<\/p>\n<p>Es ist zwar gut, Standardl\u00f6sungen zu identifizieren und sie im Hinterkopf zu behalten, wenn du auf \u00e4hnliche Probleme st\u00f6\u00dft, aber es ist gut m\u00f6glich, dass das neue Problem, auf das du gesto\u00dfen bist, nicht genau auf die gleiche Beschreibung passt wie ein \u00e4lteres Problem. In diesem Fall k\u00f6nnte es passieren, dass du eine suboptimale L\u00f6sung implementierst und Ressourcen verschwendest.<\/p>\n<p>Design Patterns sind heute als f\u00fchrende Beispiele f\u00fcr Probleml\u00f6sungspaare etabliert, weil sie im Laufe der Zeit von Hunderten und Tausenden von Programmierern getestet und so weit wie m\u00f6glich verallgemeinert wurden. Wenn du versuchst, diesen Aufwand zu wiederholen, indem du dir einfach eine Reihe von Problemen und L\u00f6sungen ansiehst und sie als \u00e4hnlich bezeichnest, k\u00f6nntest du deinem Code viel mehr Schaden zuf\u00fcgen, als du jemals erwartet h\u00e4ttest.<\/p>\n<h2>Wann solltest du Entwurfsmuster verwenden?<\/h2>\n<p>Zusammenfassend gibt es einige Anhaltspunkte, auf die du bei der Verwendung von Design Patterns achten solltest. Nicht alle davon treffen auf die Entwicklung jeder App zu, aber sie sollten dir eine gute Vorstellung davon geben, worauf du achten solltest, wenn du Design Patterns verwenden willst:<\/p>\n<ul>\n<li>Du hast ein starkes internes Entwicklerteam, das sich mit Design Patterns gut auskennt.<\/li>\n<li>Du h\u00e4ltst dich an ein SDLC-Modell, das Raum f\u00fcr ausf\u00fchrliche Diskussionen \u00fcber die Architektur deiner App l\u00e4sst, und bei diesen Diskussionen sind Design Patterns zur Sprache gekommen.<\/li>\n<li>Dieselbe Problemstellung ist in deinen Design-Diskussionen mehrfach aufgetaucht und du kennst das passende Design Pattern f\u00fcr diesen Fall.<\/li>\n<li>Du hast versucht, eine kleinere Variante deines Problems mit dem Entwurfsmuster unabh\u00e4ngig zu l\u00f6sen.<\/li>\n<li>Mit dem Entwurfsmuster sieht dein Code nicht \u00fcberm\u00e4\u00dfig komplex aus.<\/li>\n<\/ul>\n<p>Wenn ein Entwurfsmuster dein Problem l\u00f6st <em>und<\/em> dir dabei hilft, einen einfachen, wiederverwendbaren, modularen, lose gekoppelten Code zu schreiben, der nicht nach Code riecht, ist es vielleicht der richtige Weg.<\/p>\n<p>Ein weiterer guter Tipp ist, nicht alles \u00fcber Entwurfsmuster zu machen. Entwurfsmuster sollen dir helfen, Probleme zu l\u00f6sen. Sie sind keine Gesetze, an die du dich halten musst, oder Regeln, die du strikt befolgen musst. Die wichtigsten Regeln und Gesetze sind immer noch dieselben: Halte deinen Code sauber, einfach, lesbar und skalierbar. Wenn ein Entwurfsmuster dir dabei hilft, dein Problem zu l\u00f6sen, solltest du damit gut zurechtkommen.<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>JavaScript-Entwurfsmuster sind eine wunderbare Methode, um Probleme anzugehen, mit denen schon viele Programmierer\/innen im Laufe der Zeit konfrontiert wurden. Sie stellen bew\u00e4hrte L\u00f6sungen dar, die darauf abzielen, deine Codebasis sauber und lose gekoppelt zu halten.<\/p>\n<p>Heutzutage gibt es <a href=\"https:\/\/sourcemaking.com\/design-patterns-and-tips\">Hunderte von Entwurfsmustern<\/a>, die fast jedes Problem l\u00f6sen, auf das du bei der Entwicklung von Anwendungen st\u00f6\u00dft. Aber nicht jedes Entwurfsmuster l\u00f6st dein Problem <em>wirklich<\/em> jedes Mal.<\/p>\n\n<p>Wie jede <a href=\"https:\/\/kinsta.com\/de\/blog\/react-best-practices\/\">andere Programmierkonvention<\/a> sind Entwurfsmuster als Vorschl\u00e4ge zur L\u00f6sung von Problemen zu verstehen. Sie sind keine Gesetze, die du immer befolgen musst, und wenn du sie wie Gesetze behandelst, k\u00f6nntest du deinen Anwendungen am Ende gro\u00dfen Schaden zuf\u00fcgen.<\/p>\n<p>Sobald deine App fertig ist, brauchst du einen Ort, an dem du sie hosten kannst &#8211; und die <a href=\"https:\/\/sevalla.com\/application-hosting\/\">Anwendungs Hosting-L\u00f6sungen von Kinsta<\/a> geh\u00f6ren zu den schnellsten, zuverl\u00e4ssigsten und sichersten. Du musst dich nur in deinem <a href=\"https:\/\/kinsta.com\/de\/mykinsta\/\">MyKinsta-Konto<\/a> (dem benutzerdefinierten Verwaltungs-Dashboard von Kinsta) anmelden, dich mit deinem <a href=\"https:\/\/kinsta.com\/de\/blog\/was-ist-github\/\">GitHub-Repository<\/a> verbinden und loslegen! Au\u00dferdem werden dir nur die Ressourcen berechnet, die deine App nutzt.<\/p>\n<p>Welche Entwurfsmuster verwendest du regelm\u00e4\u00dfig bei deiner Arbeit als Softwareprogrammierer\/in? Oder gibt es ein Muster, das wir in dieser Liste \u00fcbersehen haben? Lass es uns in den Kommentaren unten wissen!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bei der Erstellung von JavaScript-Anwendungen kann es vorkommen, dass du Objekte auf eine bestimmte, vordefinierte Art und Weise erstellen oder eine gemeinsame Klasse wiederverwenden musst, indem &#8230;<\/p>\n","protected":false},"author":238,"featured_media":58810,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[],"topic":[952],"class_list":["post-58809","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","topic-javascript-tutorials"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.6 (Yoast SEO v24.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Ein umfassender Leitfaden zu JavaScript Entwurfsmustern<\/title>\n<meta name=\"description\" content=\"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern\" \/>\n<meta property=\"og:description\" content=\"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-14T08:27:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-07-27T10:07:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1460\" \/>\n\t<meta property=\"og:image:height\" content=\"730\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Kumar Harsh\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:description\" content=\"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png\" \/>\n<meta name=\"twitter:creator\" content=\"@Kinsta_DE\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_DE\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kumar Harsh\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"51\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\"},\"author\":{\"name\":\"Kumar Harsh\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9\"},\"headline\":\"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern\",\"datePublished\":\"2023-02-14T08:27:38+00:00\",\"dateModified\":\"2023-07-27T10:07:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\"},\"wordCount\":5919,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png\",\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\",\"url\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\",\"name\":\"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png\",\"datePublished\":\"2023-02-14T08:27:38+00:00\",\"dateModified\":\"2023-07-27T10:07:59+00:00\",\"description\":\"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png\",\"contentUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png\",\"width\":1460,\"height\":730},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript-Tutorials\",\"item\":\"https:\/\/kinsta.com\/de\/thema\/javascript-tutorials\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/de\/#website\",\"url\":\"https:\/\/kinsta.com\/de\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Schnelle, sichere und hochwertige Hosting-L\u00f6sungen\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/de\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/\",\"https:\/\/x.com\/Kinsta_DE\",\"https:\/\/www.instagram.com\/kinstahosting\/\",\"https:\/\/www.linkedin.com\/company\/kinsta\/\",\"https:\/\/www.pinterest.com\/kinstahosting\/\",\"https:\/\/www.youtube.com\/c\/Kinsta\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9\",\"name\":\"Kumar Harsh\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/de2d8d6273bdcc3dfa2f8270428f95b2?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/de2d8d6273bdcc3dfa2f8270428f95b2?s=96&d=mm&r=g\",\"caption\":\"Kumar Harsh\"},\"description\":\"Kumar is a software developer and a technical author based in India. He specializes in JavaScript and DevOps. You can learn more about his work on his website.\",\"sameAs\":[\"https:\/\/kumarharsh.me\"],\"url\":\"https:\/\/kinsta.com\/de\/blog\/author\/kumarharsh\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern","description":"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/","og_locale":"de_DE","og_type":"article","og_title":"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern","og_description":"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.","og_url":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/","article_published_time":"2023-02-14T08:27:38+00:00","article_modified_time":"2023-07-27T10:07:59+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png","type":"image\/png"}],"author":"Kumar Harsh","twitter_card":"summary_large_image","twitter_description":"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.","twitter_image":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png","twitter_creator":"@Kinsta_DE","twitter_site":"@Kinsta_DE","twitter_misc":{"Verfasst von":"Kumar Harsh","Gesch\u00e4tzte Lesezeit":"51\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/"},"author":{"name":"Kumar Harsh","@id":"https:\/\/kinsta.com\/de\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9"},"headline":"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern","datePublished":"2023-02-14T08:27:38+00:00","dateModified":"2023-07-27T10:07:59+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/"},"wordCount":5919,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/de\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png","inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/","url":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/","name":"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern","isPartOf":{"@id":"https:\/\/kinsta.com\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png","datePublished":"2023-02-14T08:27:38+00:00","dateModified":"2023-07-27T10:07:59+00:00","description":"Es gibt viele JavaScript-Entwurfsmuster, mit denen du viel Zeit und M\u00fche sparen kannst. In diesem Beitrag lernst du diese wiederverwendbaren L\u00f6sungen kennen.","breadcrumb":{"@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#primaryimage","url":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png","contentUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/02\/javascript-design-patterns.png","width":1460,"height":730},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/de\/blog\/javascript-entwurfsmuster\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/de\/"},{"@type":"ListItem","position":2,"name":"JavaScript-Tutorials","item":"https:\/\/kinsta.com\/de\/thema\/javascript-tutorials\/"},{"@type":"ListItem","position":3,"name":"Ein umfassender Leitfaden zu JavaScript Entwurfsmustern"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/de\/#website","url":"https:\/\/kinsta.com\/de\/","name":"Kinsta\u00ae","description":"Schnelle, sichere und hochwertige Hosting-L\u00f6sungen","publisher":{"@id":"https:\/\/kinsta.com\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/de\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/","https:\/\/x.com\/Kinsta_DE","https:\/\/www.instagram.com\/kinstahosting\/","https:\/\/www.linkedin.com\/company\/kinsta\/","https:\/\/www.pinterest.com\/kinstahosting\/","https:\/\/www.youtube.com\/c\/Kinsta"]},{"@type":"Person","@id":"https:\/\/kinsta.com\/de\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9","name":"Kumar Harsh","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/kinsta.com\/de\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/de2d8d6273bdcc3dfa2f8270428f95b2?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/de2d8d6273bdcc3dfa2f8270428f95b2?s=96&d=mm&r=g","caption":"Kumar Harsh"},"description":"Kumar is a software developer and a technical author based in India. He specializes in JavaScript and DevOps. You can learn more about his work on his website.","sameAs":["https:\/\/kumarharsh.me"],"url":"https:\/\/kinsta.com\/de\/blog\/author\/kumarharsh\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts\/58809","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/users\/238"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/comments?post=58809"}],"version-history":[{"count":10,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts\/58809\/revisions"}],"predecessor-version":[{"id":58960,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts\/58809\/revisions\/58960"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/it"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/pt"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/fr"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/de"},{"embeddable":true,"hreflang":"ja","title":"Japanese","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/jp"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/nl"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/es"},{"embeddable":true,"hreflang":"sv","title":"Swedish","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/se"},{"embeddable":true,"hreflang":"da","title":"Danish","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/translations\/dk"},{"href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/58809\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/media\/58810"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/media?parent=58809"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/tags?post=58809"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/topic?post=58809"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}