{"id":48667,"date":"2023-02-14T09:36:12","date_gmt":"2023-02-14T08:36:12","guid":{"rendered":"https:\/\/kinsta.com\/dk\/?p=48667&#038;preview=true&#038;preview_id=48667"},"modified":"2023-08-24T10:30:14","modified_gmt":"2023-08-24T09:30:14","slug":"javascript-designmoenstre","status":"publish","type":"post","link":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/","title":{"rendered":"En omfattende guide til JavaScript-designm\u00f8nstre"},"content":{"rendered":"<p>N\u00e5r du bygger <a href=\"https:\/\/kinsta.com\/blog\/what-is-javascript\/\">JavaScript-<\/a>applikationer, kan du st\u00f8de p\u00e5 scenarier, hvor du skal bygge objekter p\u00e5 en bestemt, foruddefineret m\u00e5de eller genbruge en f\u00e6lles klasse ved at \u00e6ndre eller tilpasse den til flere anvendelsestilf\u00e6lde.<\/p>\n<p>Det er naturligvis ikke praktisk at l\u00f8se disse problemer igen og igen.<\/p>\n<p>Det er her, JavaScript-designm\u00f8nstre kommer dig til unds\u00e6tning.<\/p>\n<p>JavaScript-designm\u00f8nstre giver dig en struktureret, gentagelig m\u00e5de at l\u00f8se almindeligt forekommende problemer i JavaScript-udviklingen p\u00e5.<\/p>\n<p>I denne vejledning vil vi se n\u00e6rmere p\u00e5, hvad JavaScript-designm\u00f8nstre er, og hvordan du kan bruge dem i dine JavaScript-apps.<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>Hvad er et JavaScript-designm\u00f8nster?<\/h2>\n<p>JavaScript-designm\u00f8nstre er gentagelige skabelonl\u00f8sninger til hyppigt forekommende problemer i JavaScript-appudvikling.<\/p>\n<p>Ideen er enkel: Programm\u00f8rer over hele verden har siden udviklingens begyndelse st\u00e5et over for s\u00e6t af tilbagevendende problemer, n\u00e5r de har <a href=\"https:\/\/kinsta.com\/dk\/blog\/applikationsudvikler\/\">udviklet apps<\/a>. Med tiden har nogle udviklere valgt at dokumentere gennempr\u00f8vede m\u00e5der at l\u00f8se disse problemer p\u00e5, s\u00e5 andre nemt kan henvise til l\u00f8sningerne.<\/p>\n<p>Efterh\u00e5nden som flere og flere udviklere valgte at bruge disse l\u00f8sninger og anerkendte deres effektivitet i l\u00f8sningen af deres problemer, blev de accepteret som en standardmetode til probleml\u00f8sning og fik navnet &#8220;designm\u00f8nstre&#8221;<\/p>\n<p>Efterh\u00e5nden som betydningen af designm\u00f8nstre blev bedre forst\u00e5et, blev disse videreudviklet og standardiseret. De fleste moderne designm\u00f8nstre har nu en defineret struktur, er organiseret under flere kategorier og undervises i datalogi-relaterede uddannelser som selvst\u00e6ndige emner.<\/p>\n<h2>Typer af JavaScript-designm\u00f8nstre<\/h2>\n<p>Her er nogle af de mest popul\u00e6re klassifikationer af JavaScript-designm\u00f8nstre.<\/p>\n<h3>Creational<\/h3>\n<p>Kreative designm\u00f8nstre er m\u00f8nstre, der hj\u00e6lper med at l\u00f8se problemer omkring oprettelse og h\u00e5ndtering af nye objektinstanser i JavaScript. Det kan v\u00e6re s\u00e5 simpelt som at begr\u00e6nse en klasse til kun at have \u00e9t objekt eller s\u00e5 komplekst som at definere en indviklet metode til at h\u00e5ndplukke og tilf\u00f8je hver enkelt funktion i et JavaScript-objekt.<\/p>\n<p>Nogle eksempler p\u00e5 skabende designm\u00f8nstre omfatter bl.a. Singleton, Factory, Abstract Factory og Builder.<\/p>\n<h3>Strukturel<\/h3>\n<p>Strukturelle designm\u00f8nstre er m\u00f8nstre, der hj\u00e6lper med at l\u00f8se problemer omkring h\u00e5ndtering af JavaScript-objekternes struktur (eller scheme). Disse problemer kan f.eks. v\u00e6re at skabe et forhold mellem to forskellige objekter eller at abstrahere nogle funktioner i et objekt for specifikke brugere.<\/p>\n<p>Et par eksempler p\u00e5 strukturelle designm\u00f8nstre er Adapter, Bridge, Composite og Facade.<\/p>\n<h3>Adf\u00e6rdsm\u00e6ssigt<\/h3>\n<p>Adf\u00e6rdsm\u00e6ssige designm\u00f8nstre er m\u00f8nstre, der hj\u00e6lper med at l\u00f8se problemer omkring, hvordan kontrol (og ansvar) overf\u00f8res mellem forskellige objekter. Disse problemer kan omfatte kontrol af adgangen til en linket liste eller oprettelse af en enkelt enhed, der kan kontrollere adgangen til flere typer objekter.<\/p>\n<p>Nogle eksempler p\u00e5 adf\u00e6rdsm\u00e6ssige designm\u00f8nstre omfatter Command, Iterator, Memento og Observer.<\/p>\n<h3>Concurrency<\/h3>\n<p>Concurrency-designm\u00f8nstre er m\u00f8nstre, der hj\u00e6lper med at l\u00f8se problemer omkring multithreading og multitasking. Disse problemer kan omfatte opretholdelse af et aktivt objekt blandt flere tilg\u00e6ngelige objekter eller h\u00e5ndtering af flere begivenheder, der leveres til et system, ved at demultiplexe indg\u00e5ende input og h\u00e5ndtere det stykke for stykke.<\/p>\n<p>Et par eksempler p\u00e5 samtidighedsdesignm\u00f8nstre omfatter aktivt objekt, nuclear react og scheduler.<\/p>\n<h3>Arkitektonisk<\/h3>\n<p>Arkitektoniske designm\u00f8nstre er m\u00f8nstre, der hj\u00e6lper med at l\u00f8se problemer omkring <a href=\"https:\/\/kinsta.com\/dk\/blog\/web-applikation-arkitektur\/\">softwaredesign<\/a> i bred forstand. De er generelt relateret til, hvordan man designer sit system og sikrer h\u00f8j tilg\u00e6ngelighed, mindsker risici og <a href=\"https:\/\/kinsta.com\/dk\/blog\/application-performance-monitoring\/\">undg\u00e5r flaskehalse i ydeevnen<\/a>.<\/p>\n<p>To eksempler p\u00e5 arkitektoniske designm\u00f8nstre er MVC og MVVM.<\/p>\n<h2>Elementer i et designm\u00f8nster<\/h2>\n<p>N\u00e6sten alle designm\u00f8nstre kan opdeles i et s\u00e6t af fire vigtige komponenter. De er:<\/p>\n<ul>\n<li><strong>M\u00f8nsternavn<\/strong>: Dette bruges til at identificere et designm\u00f8nster, mens der kommunikeres med andre brugere. Eksempler omfatter &#8220;singleton&#8221;, &#8220;prototype&#8221; og flere andre.<\/li>\n<li><strong>Problem<\/strong>: Dette beskriver form\u00e5let med designm\u00f8nstret. Det er en lille beskrivelse af det problem, som designm\u00f8nstret fors\u00f8ger at l\u00f8se. Det kan endda indeholde et eksempelscenarie for bedre at forklare problemet. Det kan ogs\u00e5 indeholde en liste over betingelser, der skal v\u00e6re opfyldt, for at et designm\u00f8nster fuldt ud l\u00f8ser det underliggende problem.<\/li>\n<li><strong>L\u00f8sning<\/strong>: Dette er l\u00f8sningen p\u00e5 det aktuelle problem, der best\u00e5r af elementer som klasser, metoder, gr\u00e6nseflader osv. Det er her, hovedparten af et designm\u00f8nster ligger &#8211; det indeb\u00e6rer relationer, ansvar og samarbejdspartnere for forskellige elementer, som er klart defineret.<\/li>\n<li><strong>Resultater<\/strong>: Dette er en analyse af, hvor godt m\u00f8nstret var i stand til at l\u00f8se problemet. Ting som plads- og tidsforbrug diskuteres sammen med alternative tilgange til at l\u00f8se det samme problem.<\/li>\n<\/ul>\n<p>Hvis du \u00f8nsker at l\u00e6re mere om designm\u00f8nstre og deres tilblivelse, har MSU nogle <a href=\"https:\/\/www.cse.msu.edu\/~cse870\/Lectures\/SS2005\/08-design-patterns.ppt\">kortfattede studiematerialer<\/a>, som du kan henvise til.<\/p>\n<h2>Hvorfor skal du bruge designm\u00f8nstre?<\/h2>\n<p>Der er flere grunde til, at du \u00f8nsker at bruge designm\u00f8nstre:<\/p>\n<ul>\n<li><strong>De er gennempr\u00f8vede og testede<\/strong>: Med et designm\u00f8nster har du en afpr\u00f8vet l\u00f8sning p\u00e5 dit problem (s\u00e5 l\u00e6nge designm\u00f8nsteret passer til beskrivelsen af dit problem). Du beh\u00f8ver ikke at spilde tid p\u00e5 at lede efter alternative l\u00f8sninger, og du kan v\u00e6re sikker p\u00e5, at du har en l\u00f8sning, der tager sig af den grundl\u00e6ggende optimering af ydeevnen for dig.<\/li>\n<li><strong>De er nemme at forst\u00e5<\/strong>: Designm\u00f8nstre er beregnet til at v\u00e6re sm\u00e5, enkle og lette at forst\u00e5. Du beh\u00f8ver ikke at v\u00e6re en specialiseret programm\u00f8r, der har arbejdet i en bestemt branche i \u00e5rtier for at forst\u00e5, hvilket designm\u00f8nster du skal bruge. De er med vilje generiske (ikke begr\u00e6nset til et bestemt programmeringssprog) og kan forst\u00e5s af alle, der har tilstr\u00e6kkelige probleml\u00f8sningsevner. Det hj\u00e6lper ogs\u00e5, n\u00e5r der sker et skift i dit tekniske team: Et stykke kode, der er baseret p\u00e5 et designm\u00f8nster, er lettere at forst\u00e5 for enhver ny softwareudvikler.<\/li>\n<\/ul>\n<ul>\n<li><strong>De er enkle at implementere<\/strong>: De fleste designm\u00f8nstre er meget enkle, som du vil se senere i vores artikel. Du beh\u00f8ver ikke at kende flere <a href=\"https:\/\/kinsta.com\/blog\/python-object-oriented-programming\/\">programmeringsbegreber<\/a> for at implementere dem i din kode.<\/li>\n<\/ul>\n<ul>\n<li><strong>De foresl\u00e5r en kodearkitektur, der er let genanvendelig<\/strong>: Genanvendelighed og <a href=\"https:\/\/kinsta.com\/blog\/html-best-practices\/\">renlighed af kode er st\u00e6rkt opmuntret<\/a> i hele den tekniske industri, og designm\u00f8nstre kan hj\u00e6lpe dig med at opn\u00e5 dette. Da disse m\u00f8nstre er en standardiseret m\u00e5de at l\u00f8se problemer p\u00e5, har deres designere s\u00f8rget for at sikre, at den omfattende app-arkitektur forbliver genanvendelig, fleksibel og kompatibel med de fleste former for kodeskrift.<\/li>\n<\/ul>\n<ul>\n<li><strong>De sparer tid og app-st\u00f8rrelse<\/strong>: En af de st\u00f8rste fordele ved at stole p\u00e5 et standards\u00e6t af l\u00f8sninger er, at de hj\u00e6lper dig med at spare tid, n\u00e5r du implementerer dem. Der er en god chance for, at hele dit udviklingsteam kender designm\u00f8nstre godt, s\u00e5 det bliver lettere for dem at <a href=\"https:\/\/kinsta.com\/blog\/microsoft-teams-vs-slack\/\">planl\u00e6gge, kommunikere og samarbejde<\/a>, n\u00e5r de implementerer dem. Afpr\u00f8vede og testede l\u00f8sninger betyder, at der er en god chance for, at du ikke ender med at l\u00e6kke ressourcer eller tage en omvej, mens du bygger en eller anden funktion, hvilket sparer dig b\u00e5de tid og plads. Desuden giver de fleste <a href=\"https:\/\/kinsta.com\/blog\/best-programming-language-to-learn\/\">programmeringssprog<\/a> dig standardskabelonbiblioteker, som allerede implementerer nogle almindelige designm\u00f8nstre som Iterator og Observer.<\/li>\n<\/ul>\n<h2>Top 20 JavaScript-designm\u00f8nstre, som du skal mestre<\/h2>\n<p>Nu hvor du forst\u00e5r, hvad et designm\u00f8nster best\u00e5r af, og hvorfor du har brug for dem, skal vi dykke dybere ned i, hvordan nogle af de mest almindeligt anvendte JavaScript-designm\u00f8nstre kan implementeres i en <a href=\"https:\/\/kinsta.com\/blog\/node-js-apps\/\">JavaScript-app<\/a>.<\/p>\n<h3>Creational<\/h3>\n<p>Lad os starte diskussionen med nogle grundl\u00e6ggende, kreative designm\u00f8nstre der er nemme at l\u00e6re.<\/p>\n<h4>1. Singleton<\/h4>\n<p>Singleton-m\u00f8nsteret er et af de mest almindeligt anvendte designm\u00f8nstre i hele softwareudviklingsbranchen. Det problem, som det har til form\u00e5l at l\u00f8se, er kun at vedligeholde en enkelt instans af en klasse. Dette kan v\u00e6re praktisk, n\u00e5r der skal instantieres objekter, der er ressourcekr\u00e6vende, f.eks. databaseh\u00e5ndterer.<\/p>\n<p>Her er hvordan du kan implementere det i JavaScript:<\/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>Selv om det tjener form\u00e5let godt, er Singleton-m\u00f8nstret kendt for at g\u00f8re debugging vanskelig, da det maskerer afh\u00e6ngigheder og kontrollerer adgangen til initialisering eller destruktion af en klasses instanser.<\/p>\n<h4>2. Factory<\/h4>\n<p>Factory-metoden er ogs\u00e5 et af de mest popul\u00e6re designm\u00f8nstre. Det problem, som Factory-metoden har til form\u00e5l at l\u00f8se, er at skabe objekter uden at bruge den konventionelle konstrukt\u00f8r. I stedet tager den konfigurationen (eller beskrivelsen) af det \u00f8nskede objekt ind og returnerer det nyligt oprettede objekt.<\/p>\n<p>Her er hvordan du kan implementere den i JavaScript:<\/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>Factory-designm\u00f8nsteret styrer, hvordan objekterne oprettes, og giver dig en hurtig m\u00e5de at oprette nye objekter p\u00e5 samt en ensartet gr\u00e6nseflade, der definerer de egenskaber, som dine objekter skal have. Du kan tilf\u00f8je lige s\u00e5 mange hunderacer, som du vil, men s\u00e5 l\u00e6nge de metoder og egenskaber, der uds\u00e6ttes af racetyperne, forbliver de samme, vil de fungere up\u00e5klageligt.<\/p>\n<p>Bem\u00e6rk dog, at Factory-m\u00f8nsteret ofte kan f\u00f8re til et stort antal klasser, som kan v\u00e6re vanskelige at administrere.<\/p>\n<h4>3. Abstrakt fabrik<\/h4>\n<p>Metoden Abstract Factory tager Factory-metoden et niveau op ved at g\u00f8re fabrikker abstrakte og dermed udskiftelige, uden at det kaldende milj\u00f8 kender den n\u00f8jagtige anvendte fabrik eller dens interne arbejdsgange. Det kaldende milj\u00f8 ved kun, at alle fabrikker har et s\u00e6t f\u00e6lles metoder, som det kan kalde for at udf\u00f8re instantieringshandlingen.<\/p>\n<p>S\u00e5dan kan det implementeres ved hj\u00e6lp af det foreg\u00e5ende eksempel:<\/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>Det abstrakte fabriksm\u00f8nster g\u00f8r det nemt for dig at udveksle konkrete fabrikker let, og det er med til at fremme ensartethed mellem fabrikker og de produkter, der oprettes. Det kan dog blive sv\u00e6rt at introducere nye typer produkter, da du skal foretage \u00e6ndringer i flere klasser for at f\u00e5 plads til nye metoder\/egenskaber.<\/p>\n<h4>4. Builder<\/h4>\n<p>Builder-m\u00f8nstret er et af de mest komplekse, men fleksible kreative JavaScript-designm\u00f8nstre. Det giver dig mulighed for at bygge hver funktion ind i dit produkt en efter en, hvilket giver dig fuld kontrol over, hvordan dit objekt er bygget op, mens du stadig abstraherer de interne detaljer v\u00e6k.<\/p>\n<p>I det indviklede eksempel nedenfor kan du se Builder-designm\u00f8nstret i aktion sammen med Director, der hj\u00e6lper dig med at lave pizzaer!<\/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 kan parre Builder med en Director, som det fremg\u00e5r af klassen <code>PizzaShop<\/code> i eksemplet ovenfor, for p\u00e5 forh\u00e5nd at definere et s\u00e6t trin, der skal f\u00f8lges hver gang for at bygge en standardvariant af dit produkt, dvs. en specifik opskrift p\u00e5 dine pizzaer.<\/p>\n<p>Det eneste problem med dette designm\u00f8nster er, at det er ret kompliceret at oprette og vedligeholde. Tilf\u00f8jelse af nye funktioner p\u00e5 denne m\u00e5de er dog enklere end Factory-metoden.<\/p>\n<h4>5. Prototype<\/h4>\n<p>Prototype-designm\u00f8nstret er en hurtig og enkel m\u00e5de at skabe nye objekter ud fra eksisterende objekter ved at klone dem.<\/p>\n<p>Der oprettes f\u00f8rst et prototypeobjekt, som kan klones flere gange for at oprette nye objekter. Det er praktisk, n\u00e5r det er mere ressourcekr\u00e6vende at instantiere et objekt direkte end at oprette en kopi af et eksisterende objekt.<\/p>\n<p>I eksemplet nedenfor kan du se, hvordan du kan bruge Prototype-m\u00f8nsteret til at oprette nye dokumenter baseret p\u00e5 et fastsat skabelondokument:<\/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>Prototype-metoden fungerer godt i tilf\u00e6lde, hvor en stor del af dine objekter deler de samme v\u00e6rdier, eller n\u00e5r det er ret dyrt at oprette et nyt objekt i det hele taget. Det f\u00f8les dog som overkill i tilf\u00e6lde, hvor du ikke har brug for mere end et par instanser af klassen.<\/p>\n<h3>Strukturel<\/h3>\n<p>Strukturelle designm\u00f8nstre hj\u00e6lper dig med at organisere din forretningslogik ved at give dig gennempr\u00f8vede m\u00e5der at strukturere dine klasser p\u00e5. Der findes en r\u00e6kke forskellige strukturelle designm\u00f8nstre, som hver is\u00e6r tager h\u00f8jde for unikke brugssituationer.<\/p>\n<h4>6. Adapter<\/h4>\n<p>Et almindeligt problem, n\u00e5r man bygger apps, er at tillade samarbejde mellem inkompatible klasser.<\/p>\n<p>Et godt eksempel til at forst\u00e5 dette er samtidig med at man opretholder bagudkompatibilitet. Hvis du skriver en ny version af en klasse, vil du naturligvis gerne have, at den let kan bruges alle de steder, hvor den gamle version fungerede. Hvis du imidlertid foretager brudte \u00e6ndringer som f.eks. fjernelse eller opdatering af metoder, der var afg\u00f8rende for, at den gamle version fungerede, kan du ende med en klasse, som kr\u00e6ver, at alle dens klienter skal opdateres for at kunne k\u00f8re.<\/p>\n<p>I s\u00e5danne tilf\u00e6lde kan Adapter-designm\u00f8nstret hj\u00e6lpe.<\/p>\n<p>Adapter-designm\u00f8nstret giver dig en abstraktion, der bygger bro over kl\u00f8ften mellem den nye klasses metoder og egenskaber og den gamle klasses metoder og egenskaber. Den har den samme gr\u00e6nseflade som den gamle klasse, men den indeholder logik til at mappe gamle metoder til de nye metoder for at udf\u00f8re lignende operationer. Dette svarer til, hvordan en stikkontakt fungerer som en adapter mellem et amerikansk og et europ\u00e6isk stik.<\/p>\n<p>Her er et eksempel:<\/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>Det st\u00f8rste problem med dette designm\u00f8nster er, at det tilf\u00f8jer kompleksitet til din kildekode. Du skulle allerede vedligeholde to forskellige klasser, og nu har du endnu en klasse &#8211; Adapteren &#8211; at vedligeholde.<\/p>\n<h4>7. Bridge<\/h4>\n<p>Bridge-designm\u00f8nsteret udvider Adapter-m\u00f8nsteret og giver b\u00e5de klassen og klienten separate gr\u00e6nseflader, s\u00e5 de begge kan fungere, selv i tilf\u00e6lde af inkompatible native gr\u00e6nseflader.<\/p>\n<p>Det hj\u00e6lper med at udvikle en meget l\u00f8st koblet gr\u00e6nseflade mellem de to typer objekter. Det er ogs\u00e5 med til at forbedre udvidelsesmulighederne for gr\u00e6nsefladerne og deres implementeringer for at opn\u00e5 maksimal fleksibilitet.<\/p>\n<p>S\u00e5dan kan du bruge det:<\/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>Som du m\u00e5ske allerede har g\u00e6ttet, \u00f8ger Bridge-m\u00f8nsteret kompleksiteten af kodebasen betydeligt. Desuden ender de fleste gr\u00e6nseflader normalt med kun \u00e9n implementering i virkelige brugstilf\u00e6lde, s\u00e5 du har ikke rigtig meget gavn af kodegenbrugeligheden.<\/p>\n<h4>8. Composite<\/h4>\n<p>Designm\u00f8nstret Composite hj\u00e6lper dig med at strukturere og administrere lignende objekter og enheder p\u00e5 en nem m\u00e5de. Den grundl\u00e6ggende id\u00e9 bag Composite-m\u00f8nstret er, at objekter og deres logiske containere kan repr\u00e6senteres ved hj\u00e6lp af en enkelt abstrakt klasse (som kan gemme data\/metoder relateret til objektet og referencer til sig selv for containerens vedkommende).<\/p>\n<p>Det giver mest mening at bruge Composite-m\u00f8nstret, n\u00e5r din datamodel ligner en tr\u00e6struktur. Du b\u00f8r dog ikke fors\u00f8ge at omdanne en datamodel uden tr\u00e6er til en tr\u00e6lignende datamodel blot for at bruge Composite-m\u00f8nsteret, da det ofte kan fjerne en stor del af fleksibiliteten.<\/p>\n<p>I eksemplet nedenfor kan du se, hvordan du kan bruge Composite-designm\u00f8nsteret til at konstruere et emballagesystem til e-handelsprodukter, der ogs\u00e5 kan beregne den samlede ordrev\u00e6rdi pr. pakke:<\/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>Den st\u00f8rste ulempe ved at bruge Composite-m\u00f8nstret er, at \u00e6ndringer af komponentgr\u00e6nsefladerne kan v\u00e6re meget udfordrende i fremtiden. Det tager tid og kr\u00e6fter at designe gr\u00e6nsefladerne, og datamodellens tr\u00e6agtige karakter kan g\u00f8re det meget vanskeligt at foretage de \u00e6ndringer, man \u00f8nsker.<\/p>\n<h4>9. Decorator<\/h4>\n<p>Decorator-m\u00f8nstret hj\u00e6lper dig med at tilf\u00f8je nye funktioner til eksisterende objekter ved blot at pakke dem ind i et nyt objekt. Det svarer til, hvordan du kan pakke en allerede indpakket gave\u00e6ske ind i nyt gavepapir s\u00e5 mange gange, du vil: Hver indpakning giver dig mulighed for at tilf\u00f8je s\u00e5 mange funktioner, som du \u00f8nsker, s\u00e5 det er fantastisk p\u00e5 fleksibilitetsfronten.<\/p>\n<p>Ud fra et teknisk perspektiv er der ingen arv involveret, s\u00e5 der er st\u00f8rre frihed ved udformning af forretningslogik.<\/p>\n<p>I eksemplet nedenfor kan du se, hvordan Decorator-m\u00f8nstret hj\u00e6lper med at tilf\u00f8je flere funktioner til en standardklasse <code>Customer<\/code>:<\/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>Ulemperne ved dette m\u00f8nster er bl.a., at koden er meget kompleks, da der ikke er defineret noget standardm\u00f8nster for tilf\u00f8jelse af nye funktioner ved hj\u00e6lp af decorators. Du kan ende op med en masse ikke-uniforme og\/eller lignende decorators i slutningen af din softwareudviklings livscyklus.<\/p>\n<p>Hvis du ikke er forsigtig med at designe decorators, kan du ende med at designe nogle decorators til at v\u00e6re logisk afh\u00e6ngige af andre. Hvis dette ikke l\u00f8ses, kan fjernelse eller omstrukturering af decorators senere hen i processen \u00f8del\u00e6gge stabiliteten af din applikation.<\/p>\n<h4>10. Facade<\/h4>\n<p>N\u00e5r man bygger de fleste reelle applikationer, viser forretningslogikken sig normalt at v\u00e6re ret kompleks, n\u00e5r man er f\u00e6rdig. Du kan ende med at have flere objekter og metoder, der er involveret i udf\u00f8relsen af kerneoperationer i din app. Det kan v\u00e6re ret vanskeligt og fejlbeh\u00e6ftet at holde styr p\u00e5 deres initialiseringer, afh\u00e6ngigheder, den korrekte r\u00e6kkef\u00f8lge for udf\u00f8relse af metoder osv., hvis det ikke g\u00f8res korrekt.<\/p>\n<p>Facade-designm\u00f8nstret hj\u00e6lper dig med at skabe en abstraktion mellem det milj\u00f8, der p\u00e5kalder de ovenn\u00e6vnte operationer, og de objekter og metoder, der er involveret i udf\u00f8relsen af disse operationer. Denne abstraktion indeholder logikken til initialisering af objekterne, sporing af deres afh\u00e6ngigheder og andre vigtige aktiviteter. Det kaldende milj\u00f8 har ingen oplysninger om, hvordan en operation udf\u00f8res. Du kan frit opdatere logikken uden at foretage \u00e6ndringer i den kaldende klient.<\/p>\n<p>Her er hvordan du kan bruge det i en applikation:<\/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>En ulempe ved at bruge Facade-m\u00f8nstret er, at det tilf\u00f8jer et ekstra abstraktionslag mellem din forretningslogik og klienten, hvilket kr\u00e6ver yderligere vedligeholdelse. Oftest \u00f8ger dette den samlede kompleksitet af kodebasen.<\/p>\n<p>Derudover bliver <code>Facade<\/code> -klassen en obligatorisk afh\u00e6ngighed af din app&#8217;s funktion &#8211; hvilket betyder, at eventuelle fejl i <code>Facade<\/code> -klassen har direkte indflydelse p\u00e5 din app&#8217;s funktion.<\/p>\n<h4>11. Flyweight<\/h4>\n<p>Flyweight-m\u00f8nstret hj\u00e6lper dig med at l\u00f8se problemer, der involverer objekter med gentagende komponenter, p\u00e5 en hukommelseseffektiv m\u00e5de ved at hj\u00e6lpe dig med at genbruge de f\u00e6lles komponenter i din objektpulje. Dette er med til at reducere belastningen af hukommelsen og resulterer ogs\u00e5 i hurtigere udf\u00f8relsestider.<\/p>\n<p>I eksemplet nedenfor gemmes en stor s\u00e6tning i hukommelsen ved hj\u00e6lp af Flyweight-designm\u00f8nstret. I stedet for at lagre hvert enkelt tegn, efterh\u00e5nden som det forekommer, identificerer programmet det s\u00e6t af forskellige tegn, der er blevet brugt til at skrive afsnittet, og deres typer (tal eller alfabet) og opbygger genanvendelige flyweights for hvert tegn, der indeholder oplysninger om, hvilket tegn og hvilken type der er gemt.<\/p>\n<p>Derefter lagrer hovedarrayet blot en liste over referencer til disse flyweights i den r\u00e6kkef\u00f8lge, de forekommer i s\u00e6tningen, i stedet for at lagre en instans af karakterobjektet, hver gang det forekommer.<\/p>\n<p>Dette reducerer den hukommelse, som s\u00e6tningen bruger, med halvdelen. Husk p\u00e5, at dette er en meget grundl\u00e6ggende forklaring p\u00e5, hvordan tekstprocessorer lagrer tekst.<\/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>Som du m\u00e5ske allerede har bem\u00e6rket, \u00f8ger Flyweight-m\u00f8nsteret kompleksiteten af dit softwaredesign ved ikke at v\u00e6re s\u00e6rlig intuitivt. S\u00e5 hvis det ikke er et presserende problem for din app at spare hukommelse, kan Flyweight&#8217;s ekstra kompleksitet g\u00f8re mere skade end gavn.<\/p>\n<p>Desuden bytter Flyweights hukommelse for behandlingseffektivitet, s\u00e5 hvis du mangler CPU-cyklusser, er Flyweight ikke en god l\u00f8sning for dig.<\/p>\n<h4>12. Proxy<\/h4>\n<p>Proxy-m\u00f8nstret hj\u00e6lper dig med at erstatte et objekt med et andet objekt. Med andre ord kan proxy-objekter erstatte faktiske objekter (som de er en proxy for) og kontrollere adgangen til objektet. Disse proxyobjekter kan bruges til at udf\u00f8re nogle handlinger f\u00f8r eller efter, at en invocationforesp\u00f8rgsel er sendt videre til det faktiske objekt.<\/p>\n<p>I eksemplet nedenfor kan du se, hvordan adgangen til en databaseinstans styres via en proxy, der udf\u00f8rer nogle grundl\u00e6ggende valideringskontroller af anmodningerne, f\u00f8r de tillades:<\/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>Dette designm\u00f8nster er almindeligt anvendt i hele branchen og hj\u00e6lper med at implementere f\u00f8r- og efterudf\u00f8relsesoperationer nemt. Men ligesom alle andre designm\u00f8nstre tilf\u00f8jer det ogs\u00e5 kompleksitet til din kodebase, s\u00e5 pr\u00f8v at lade v\u00e6re med at bruge det, hvis du ikke virkelig har brug for det.<\/p>\n<p>Du skal ogs\u00e5 huske p\u00e5, at da der er et ekstra objekt involveret, n\u00e5r du foretager kald til dit egentlige objekt, kan der v\u00e6re en vis latenstid p\u00e5 grund af de ekstra behandlingsoperationer. Optimering af dit hovedobjekts ydeevne indeb\u00e6rer nu ogs\u00e5 optimering af din proxys metoder med henblik p\u00e5 ydeevne.<\/p>\n<h3>Adf\u00e6rdsm\u00e6ssig<\/h3>\n<p>Adf\u00e6rdsm\u00e6ssige designm\u00f8nstre hj\u00e6lper dig med at l\u00f8se problemer omkring, hvordan objekter interagerer med hinanden. Dette kan involvere deling eller videregivelse af ansvar\/kontrol mellem objekter for at gennemf\u00f8re s\u00e6toperationer. Det kan ogs\u00e5 involvere videregivelse\/deling af data p\u00e5 tv\u00e6rs af flere objekter p\u00e5 den mest effektive m\u00e5de muligt.<\/p>\n<h4>13. Ansvarsk\u00e6de<\/h4>\n<p>Chain of Responsibility-m\u00f8nstret er et af de enkleste adf\u00e6rdsm\u00e6ssige designm\u00f8nstre. Det er praktisk, n\u00e5r du designer logik for operationer, der kan h\u00e5ndteres af flere handlers.<\/p>\n<p>I lighed med hvordan problemeskalering fungerer i supportteams, sendes kontrollen gennem en k\u00e6de af handlere, og den handler, der er ansvarlig for at foretage handlingen, fuldf\u00f8rer operationen. Dette designm\u00f8nster bruges ofte i UI-design, hvor flere lag af komponenter kan h\u00e5ndtere en brugerinputbegivenhed, f.eks. et tryk eller et swipe.<\/p>\n<p>Nedenfor kan du se et eksempel p\u00e5 en klageskalering, der anvender ansvarsk\u00e6dem\u00f8nstret. Klagen vil blive h\u00e5ndteret af behandlerne p\u00e5 grundlag af dens alvorlighed:<\/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>Det indlysende problem med dette design er, at det er line\u00e6rt, s\u00e5 der kan v\u00e6re en vis latenstid i h\u00e5ndteringen af en operation, n\u00e5r et stort antal handlere er k\u00e6det sammen.<\/p>\n<p>At holde styr p\u00e5 alle handlers kan v\u00e6re et andet smertepunkt, da det kan blive ret rodet efter et vist antal handlers. Debugging er endnu et mareridt, da hver anmodning kan ende p\u00e5 en anden handler, hvilket g\u00f8r det sv\u00e6rt for dig at standardisere <a href=\"https:\/\/kinsta.com\/blog\/node-debug\/\">lognings- og debuggingprocessen<\/a>.<\/p>\n<h4>14. Iterator<\/h4>\n<p>Iterator-m\u00f8nstret er ret simpelt og bruges meget ofte i n\u00e6sten alle moderne objektorienterede sprog. Hvis du st\u00e5r over for at skulle gennemg\u00e5 en liste af objekter, der ikke alle er af samme type, kan normale iterationsmetoder, s\u00e5som for-loops, blive ret rodet &#8211; is\u00e6r hvis du ogs\u00e5 skriver forretningslogik indeni dem.<\/p>\n<p>Iterator-m\u00f8nstret kan hj\u00e6lpe dig med at isolere iterations- og behandlingslogikken for dine lister fra den prim\u00e6re forretningslogik.<\/p>\n<p>Her kan du se, hvordan du kan bruge det p\u00e5 en ret grundl\u00e6ggende liste med flere typer elementer:<\/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>Det siger sig selv, at dette m\u00f8nster kan v\u00e6re un\u00f8dvendigt komplekst for lister uden flere typer af elementer. Hvis der er for mange typer af elementer i en liste, kan den ogs\u00e5 blive vanskelig at administrere.<\/p>\n<p>N\u00f8glen er at identificere, om du virkelig har brug for en iterator baseret p\u00e5 din liste og dens fremtidige \u00e6ndringsmuligheder. Desuden er Iterator-m\u00f8nstret kun nyttigt i lister, og lister kan nogle gange begr\u00e6nse dig til deres line\u00e6re adgangsform. Andre datastrukturer kan nogle gange give dig st\u00f8rre ydelsesfordele.<\/p>\n<h4>15. Mediator<\/h4>\n<p>Dit applikationsdesign kan nogle gange kr\u00e6ve, at du skal lege med et stort antal forskellige objekter, der rummer forskellige former for forretningslogik og ofte er afh\u00e6ngige af hinanden. H\u00e5ndteringen af afh\u00e6ngighederne kan nogle gange blive vanskelig, da du skal holde styr p\u00e5, hvordan disse objekter udveksler data og kontrol mellem dem.<\/p>\n<p>Mediator-designm\u00f8nstret har til form\u00e5l at hj\u00e6lpe dig med at l\u00f8se dette problem ved at isolere interaktionslogikken for disse objekter i et separat objekt for sig selv.<\/p>\n<p>Dette separate objekt er kendt som mediator og er ansvarlig for at f\u00e5 arbejdet udf\u00f8rt af dine klasser p\u00e5 lavere niveau. Din klient eller det kaldende milj\u00f8 vil ogs\u00e5 interagere med mediatoren i stedet for klasserne p\u00e5 lavere niveau.<\/p>\n<p>Her er et eksempel p\u00e5 mediator-designm\u00f8nsteret i praksis:<\/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>Mens mediatoren giver dit app-design afkobling og en stor fleksibilitet, er det i sidste ende endnu en klasse, som du skal vedligeholde. Du skal vurdere, om dit design virkelig kan drage fordel af en mediator, f\u00f8r du skriver en, s\u00e5 du ikke ender med at tilf\u00f8je un\u00f8dig kompleksitet til din kodebase.<\/p>\n<p>Det er ogs\u00e5 vigtigt at huske p\u00e5, at selv om mediatorklassen ikke indeholder nogen direkte forretningslogik, indeholder den stadig en masse kode, der er afg\u00f8rende for, at din app fungerer, og som derfor hurtigt kan blive ret kompleks.<\/p>\n<h4>16. Memento<\/h4>\n<p>Versionering af objekter er et andet almindeligt problem, som du vil st\u00f8de p\u00e5, n\u00e5r du udvikler apps. Der er mange anvendelsestilf\u00e6lde, hvor du har brug for at vedligeholde et objekts historik, underst\u00f8tte nemme rollbacks og nogle gange endda underst\u00f8tte tilbagef\u00f8rsel af disse rollbacks. Det kan v\u00e6re sv\u00e6rt at skrive logikken til s\u00e5danne apps.<\/p>\n<p>Memento-designm\u00f8nstret er beregnet til at l\u00f8se dette problem nemt.<\/p>\n<p>Et memento betragtes som et \u00f8jebliksbillede af et objekt p\u00e5 et bestemt tidspunkt. Memento-designm\u00f8nstret g\u00f8r brug af disse mementoer til at bevare \u00f8jebliksbilleder af objektet, efterh\u00e5nden som det \u00e6ndres over tid. N\u00e5r du har brug for at rulle tilbage til en gammel version, kan du blot hente memento&#8217;et for det.<\/p>\n<p>Her er, hvordan du kan implementere det i en tekstbehandlingsapp:<\/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>Memento-designm\u00f8nsteret er en god l\u00f8sning til at administrere et objekts historik, men det kan blive meget ressourcekr\u00e6vende. Da hver memento n\u00e6sten er en kopi af objektet, kan det meget hurtigt fylde din app&#8217;s hukommelse, hvis det ikke bruges med m\u00e5de.<\/p>\n<p>Med et stort antal objekter kan deres livscyklusstyring ogs\u00e5 blive en ret kedelig opgave. Oven i alt dette er <code>Originator<\/code> &#8211; og <code>Caretaker<\/code> -klasserne normalt meget t\u00e6t koblet, hvilket \u00f8ger kompleksiteten af din kodebase.<\/p>\n<h4>17. Observer<\/h4>\n<p>Observer-m\u00f8nstret giver en alternativ l\u00f8sning p\u00e5 problemet med interaktion mellem flere objekter (som tidligere er set i Mediator-m\u00f8nstret).<\/p>\n<p>I stedet for at lade hvert objekt kommunikere med hinanden gennem en udpeget mediator, giver Observer-m\u00f8nstret dem mulighed for at observere hinanden. Objekter er designet til at udsende begivenheder, n\u00e5r de fors\u00f8ger at sende data eller kontrol, og andre objekter, der &#8220;lytter&#8221; til disse begivenheder, kan modtage dem og interagere p\u00e5 grundlag af deres indhold.<\/p>\n<p>Her er en simpel demonstration af udsendelse af nyhedsbreve til flere personer via Observer-m\u00f8nsteret:<\/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>Selvom Observer-m\u00f8nstret er en smart m\u00e5de at sende kontrol og data rundt p\u00e5, er det bedre egnet til situationer, hvor der er et stort antal afsendere og modtagere, der interagerer med hinanden via et begr\u00e6nset antal forbindelser. Hvis objekterne alle skulle lave en-til-en-forbindelser, ville man miste den fordel, man f\u00e5r ved at udgive og abonnere p\u00e5 begivenheder, da der altid kun vil v\u00e6re \u00e9n abonnent for hver udgiver (n\u00e5r det ville v\u00e6re bedre h\u00e5ndteret med en direkte kommunikationslinje mellem dem).<\/p>\n<p>Desuden kan Observer-designm\u00f8nstret f\u00f8re til problemer med ydeevnen, hvis abonnementsbegivenhederne ikke h\u00e5ndteres korrekt. Hvis et objekt forts\u00e6tter med at abonnere p\u00e5 et andet objekt, selv n\u00e5r det ikke er n\u00f8dvendigt, vil det <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lapsed_listener_problem\">ikke v\u00e6re berettiget til garbage collection<\/a> og vil \u00f8ge appens hukommelsesforbrug.<\/p>\n<h4>18. Tilstand<\/h4>\n<p>State-designm\u00f8nstret er et af de mest anvendte designm\u00f8nstre i hele softwareudviklingsindustrien. Popul\u00e6re <a href=\"https:\/\/kinsta.com\/dk\/blog\/javascript-biblioteker\/\">JavaScript-frameworks<\/a> som <a href=\"https:\/\/reactjs.org\/docs\/state-and-lifecycle.html\">React<\/a> og <a href=\"https:\/\/medium.com\/olricdigital\/introduction-to-state-management-in-angular-v2-ef6f5144bade\">Angular<\/a> er st\u00e6rkt afh\u00e6ngige af State-m\u00f8nstret til at administrere data og appadf\u00e6rd baseret p\u00e5 disse data.<\/p>\n<p>Kort sagt er State-designm\u00f8nstret nyttigt i situationer, hvor du kan definere definitive tilstande for en enhed (som kan v\u00e6re en komponent, en side, en app eller en maskine), og hvor enheden har en foruddefineret reaktion p\u00e5 tilstands\u00e6ndringen.<\/p>\n<p>Lad os sige, at du fors\u00f8ger at opbygge en l\u00e5neans\u00f8gningsproces. Hvert trin i ans\u00f8gningsprocessen kan defineres som en tilstand.<\/p>\n<p>Mens kunden normalt ser en lille liste over forenklede tilstande for deres ans\u00f8gning (afventende, under gennemgang, accepteret og afvist), kan der internt v\u00e6re andre trin involveret. P\u00e5 hvert af disse trin vil ans\u00f8gningen blive tildelt en bestemt person og kan have unikke krav.<\/p>\n<p>Systemet er udformet p\u00e5 en s\u00e5dan m\u00e5de, at n\u00e5r behandlingen i en tilstand er afsluttet, opdateres tilstanden til den n\u00e6ste i r\u00e6kken, og det n\u00e6ste relevante s\u00e6t trin p\u00e5begyndes.<\/p>\n<p>Her er hvordan du kan opbygge et opgavestyringssystem ved hj\u00e6lp af State-designm\u00f8nstret:<\/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>Selv om State-m\u00f8nstret g\u00f8r et godt stykke arbejde med at adskille trin i en proces, kan det blive ekstremt vanskeligt at vedligeholde i store applikationer, der har flere tilstande.<\/p>\n<p>Hvis dit procesdesign desuden tillader mere end blot at bev\u00e6ge sig line\u00e6rt gennem alle tilstande, skal du skrive og vedligeholde mere kode, da hver tilstandsovergang skal h\u00e5ndteres separat.<\/p>\n<h4>19. Strategi<\/h4>\n<p>Strategy-m\u00f8nstret, der ogs\u00e5 er kendt som Policy-m\u00f8nsteret, har til form\u00e5l at hj\u00e6lpe dig med at indkapsle og frit udveksle klasser ved hj\u00e6lp af en f\u00e6lles gr\u00e6nseflade. Dette hj\u00e6lper med at opretholde en l\u00f8s kobling mellem klienten og klasserne og giver dig mulighed for at tilf\u00f8je s\u00e5 mange implementeringer, som du \u00f8nsker.<\/p>\n<p>Strategy-m\u00f8nstret er kendt for at v\u00e6re en enorm hj\u00e6lp i situationer, hvor der er behov for den samme operation ved hj\u00e6lp af forskellige metoder\/algoritmer, eller hvor massive switch-blokke skal erstattes med mere menneskevenlig kode.<\/p>\n<p>Her er et eksempel p\u00e5 Strategy-m\u00f8nstret:<\/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>Strategy-m\u00f8nstret er fantastisk, n\u00e5r det drejer sig om at indf\u00f8re nye variationer af en enhed uden at \u00e6ndre klienterne meget. Det kan dog virke som overkill, hvis du kun har en h\u00e5ndfuld variationer, der skal implementeres.<\/p>\n<p>Desuden fjerner indkapslingen finere detaljer om hver enkelt variations interne logik, s\u00e5 din klient ikke er klar over, hvordan en variant vil opf\u00f8re sig.<\/p>\n<h4>20. Bes\u00f8gende<\/h4>\n<p>Visitor-m\u00f8nstret har til form\u00e5l at hj\u00e6lpe dig med at g\u00f8re din kode udvidelig.<\/p>\n<p>Ideen er at stille en metode til r\u00e5dighed i klassen, der g\u00f8r det muligt for objekter fra andre klasser at foretage \u00e6ndringer i objekter fra den aktuelle klasse p\u00e5 en nem m\u00e5de. De andre objekter <em>bes\u00f8ger<\/em> det aktuelle objekt (ogs\u00e5 kaldet stedobjektet), eller den aktuelle klasse <em>accepterer <\/em>bes\u00f8gsobjekterne, og stedobjektet h\u00e5ndterer bes\u00f8get af hvert eksternt objekt p\u00e5 passende vis.<\/p>\n<p>S\u00e5dan kan du bruge det:<\/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>Den eneste fejl ved dette design er, at hver bes\u00f8gsklasse skal opdateres, n\u00e5r der tilf\u00f8jes eller \u00e6ndres et nyt sted. I tilf\u00e6lde, hvor der findes flere bes\u00f8gende og stedobjekter sammen, kan det v\u00e6re sv\u00e6rt at vedligeholde.<\/p>\n<p>Bortset fra det fungerer metoden godt til at forbedre funktionaliteten af klasser dynamisk.<\/p>\n<h2>Bedste praksis for implementering af designm\u00f8nstre<\/h2>\n<p>Nu hvor du har set de mest almindelige designm\u00f8nstre p\u00e5 tv\u00e6rs af JavaScript, er her nogle tips, som du b\u00f8r huske p\u00e5, n\u00e5r du implementerer dem.<\/p>\n<h3>V\u00e6r s\u00e6rlig omhyggelig med at forst\u00e5, om et m\u00f8nster passer til l\u00f8sningen<\/h3>\n<p>Dette tip skal anvendes, f\u00f8r du implementerer et designm\u00f8nster i din kildekode. Selv om det kan se ud som om et designm\u00f8nster er afslutningen p\u00e5 alle dine bekymringer, skal du tage et \u00f8jeblik til at analysere kritisk, om det er sandt.<\/p>\n<p>Der er mange m\u00f8nstre, der l\u00f8ser det samme problem, men som har forskellige tilgange og har forskellige konsekvenser. S\u00e5 dine kriterier for valg af et designm\u00f8nster b\u00f8r ikke kun v\u00e6re, om det l\u00f8ser dit problem eller ej &#8211; det b\u00f8r ogs\u00e5 v\u00e6re, hvor godt det l\u00f8ser dit problem, og om der er et andet m\u00f8nster, der kan pr\u00e6sentere en mere effektiv l\u00f8sning.<\/p>\n<h3>Forst\u00e5 omkostningerne ved at implementere et m\u00f8nster, f\u00f8r du g\u00e5r i gang<\/h3>\n<p>Selv om designm\u00f8nstre synes at v\u00e6re den bedste l\u00f8sning p\u00e5 alle <a href=\"https:\/\/kinsta.com\/blog\/errors-in-javascript\/\">tekniske problemer<\/a>, b\u00f8r du ikke kaste dig ud i at implementere dem i din kildekode med det samme.<\/p>\n<p>Mens du vurderer konsekvenserne af at implementere en l\u00f8sning, skal du ogs\u00e5 tage hensyn til din egen situation. Har du et stort team af softwareudviklere, der er velbevandret i at forst\u00e5 og vedligeholde designm\u00f8nstre? Eller er du en stifter i en tidlig fase med et minimalt udviklingsteam, der \u00f8nsker at frigive en hurtig MVP af dit produkt? Hvis du svarer ja til det sidste sp\u00f8rgsm\u00e5l, er designm\u00f8nstre m\u00e5ske ikke den mest optimale udviklingsmetode for dig.<\/p>\n<p>Designm\u00f8nstre f\u00f8rer ikke til omfattende genbrug af kode, medmindre de planl\u00e6gges i en meget tidlig fase af appdesignet. Hvis du tilf\u00e6ldigt bruger designm\u00f8nstre i forskellige faser, kan det f\u00f8re til en un\u00f8digt kompleks app-arkitektur, som du skal bruge uger p\u00e5 at forenkle.<\/p>\n<p>Effektiviteten af et designm\u00f8nster kan ikke bed\u00f8mmes ved hj\u00e6lp af nogen form for test. Det er dit <a href=\"https:\/\/kinsta.com\/blog\/code-review-tools\/\">teams erfaring og selvransagelse<\/a>, der vil lade dig vide, om de virker. Hvis du har tid og ressourcer til at afs\u00e6tte til disse aspekter, er det f\u00f8rst da, at designm\u00f8nstre virkelig vil l\u00f8se dine problemer.<\/p>\n<h3>G\u00f8r ikke alle l\u00f8sninger til et m\u00f8nster<\/h3>\n<p>En anden tommelfingerregel, som du skal huske p\u00e5, er at afst\u00e5 fra at fors\u00f8ge at g\u00f8re hvert eneste lille problem-l\u00f8sningspar til et designm\u00f8nster og bruge det, hvor du ser plads til det.<\/p>\n<p>Selv om det er godt at identificere standardl\u00f8sninger og huske dem, n\u00e5r du st\u00f8der p\u00e5 lignende problemer, er der en god chance for, at det nye problem, du er st\u00f8dt p\u00e5, ikke passer til n\u00f8jagtig den samme beskrivelse som et \u00e6ldre problem. I s\u00e5 fald kan du ende med at implementere en suboptimal l\u00f8sning og spilde ressourcer.<\/p>\n<p>Designm\u00f8nstre er i dag etableret som f\u00f8rende eksempler p\u00e5 problem-l\u00f8sningspar, fordi de er blevet afpr\u00f8vet af hundred- og tusindvis af programm\u00f8rer gennem tiden og er blevet generaliseret s\u00e5 meget som muligt. Hvis du fors\u00f8ger at gentage denne indsats ved blot at se p\u00e5 en masse problemer og l\u00f8sninger og kalde dem ens, kan du ende med at g\u00f8re meget mere skade p\u00e5 din kode, end du nogensinde havde forventet.<\/p>\n<h2>Hvorn\u00e5r skal du bruge designm\u00f8nstre?<\/h2>\n<p>For at opsummere er her et par stikord, som du b\u00f8r holde \u00f8je med for at bruge designm\u00f8nstre. De g\u00e6lder ikke alle sammen for udviklingen af alle apps, men de burde give dig en god id\u00e9 om, hvad du skal v\u00e6re opm\u00e6rksom p\u00e5, n\u00e5r du overvejer at bruge designm\u00f8nstre:<\/p>\n<ul>\n<li>Du har et st\u00e6rkt internt team af udviklere, der har en god forst\u00e5else for designm\u00f8nstre.<\/li>\n<li>Du f\u00f8lger en SDLC-model, der giver plads til dybdeg\u00e5ende diskussioner om arkitekturen af din app, og designm\u00f8nstre er blevet n\u00e6vnt i disse diskussioner.<\/li>\n<li>Det samme s\u00e6t af problemer er dukket op flere gange i dine designdiskussioner, og du kender det designm\u00f8nster, der passer til sagen.<\/li>\n<li>Du har fors\u00f8gt at l\u00f8se en mindre variation af dit problem uafh\u00e6ngigt af designm\u00f8nstret.<\/li>\n<li>Med designm\u00f8nsteret p\u00e5 plads ser din kode ikke alt for kompleks ud.<\/li>\n<\/ul>\n<p>Hvis et designm\u00f8nster l\u00f8ser dit problem <em>og<\/em> hj\u00e6lper dig med at skrive kode, der er enkel, genanvendelig, modul\u00e6r, l\u00f8st koblet og fri for &#8220;kodelugt&#8221;, er det m\u00e5ske den rigtige vej at g\u00e5.<\/p>\n<p>Et andet godt tip at huske p\u00e5 er at undg\u00e5 at g\u00f8re alting til et designm\u00f8nster. Designm\u00f8nstre er beregnet til at hj\u00e6lpe dig med at l\u00f8se problemer. De er ikke love, som du skal overholde, eller regler, som du skal f\u00f8lge strengt. De ultimative regler og love er stadig de samme: Hold din kode ren, enkel, l\u00e6sbar og skalerbar. Hvis et designm\u00f8nster hj\u00e6lper dig med at g\u00f8re dette, samtidig med at det l\u00f8ser dit problem, b\u00f8r du sagtens kunne k\u00f8re med det.<\/p>\n<h2>Opsummering<\/h2>\n<p>JavaScript-designm\u00f8nstre er en vidunderlig m\u00e5de at gribe problemer an p\u00e5, som flere programm\u00f8rer har st\u00e5et over for i tidens l\u00f8b. De pr\u00e6senterer gennempr\u00f8vede l\u00f8sninger, der bestr\u00e6ber sig p\u00e5 at holde din kodebase ren og l\u00f8st koblet.<\/p>\n<p>I dag er der <a href=\"https:\/\/sourcemaking.com\/design-patterns-and-tips\">hundredvis af designm\u00f8nstre<\/a> til r\u00e5dighed, som l\u00f8ser n\u00e6sten alle de problemer, du st\u00f8der p\u00e5, n\u00e5r du bygger apps. Det er dog ikke alle designm\u00f8nstre, der <em>virkelig<\/em> vil l\u00f8se dit problem hver gang.<\/p>\n<p>Ligesom enhver <a href=\"https:\/\/kinsta.com\/dk\/blog\/react-bedste-praksisser\/\">anden programmeringskonvention<\/a> skal designm\u00f8nstre opfattes som forslag til l\u00f8sning af problemer. De er ikke love, der skal f\u00f8lges hele tiden, og hvis du behandler dem som love, kan du ende med at g\u00f8re stor skade p\u00e5 dine apps.<\/p>\n<p>N\u00e5r din app er f\u00e6rdig, har du brug for et sted at hoste den &#8211; og <a href=\"https:\/\/sevalla.com\/application-hosting\/\">Kinstas l\u00f8sninger til applikationshosting<\/a> er f\u00f8rende blandt de hurtigste, mest p\u00e5lidelige og mest sikre. Du skal blot logge ind p\u00e5 din <a href=\"https:\/\/kinsta.com\/dk\/mykinsta\/\">MyKinsta-konto<\/a> (Kinstas brugerdefinerede administrative dashboard), oprette forbindelse til dit <a href=\"https:\/\/kinsta.com\/blog\/what-is-github\/\">GitHub-repositorium<\/a> og starte! Desuden bliver du kun opkr\u00e6vet for de ressourcer, som din app bruger.<\/p>\n<p>Hvilke designm\u00f8nstre bruger du regelm\u00e6ssigt i dit job som softwareprogramm\u00f8r? Eller er der et m\u00f8nster, som vi har overset p\u00e5 listen? Lad os vide det i kommentarerne nedenfor!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>N\u00e5r du bygger JavaScript-applikationer, kan du st\u00f8de p\u00e5 scenarier, hvor du skal bygge objekter p\u00e5 en bestemt, foruddefineret m\u00e5de eller genbruge en f\u00e6lles klasse ved at &#8230;<\/p>\n","protected":false},"author":238,"featured_media":48668,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[],"topic":[706],"class_list":["post-48667","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>En omfattende guide til JavaScript-designm\u00f8nstre<\/title>\n<meta name=\"description\" content=\"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.\" \/>\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\/dk\/blog\/javascript-designmoenstre\/\" \/>\n<meta property=\"og:locale\" content=\"da_DK\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"En omfattende guide til JavaScript-designm\u00f8nstre\" \/>\n<meta property=\"og:description\" content=\"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Kinsta-Danmark-122855885298660\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-14T08:36:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-08-24T09:30:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/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=\"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png\" \/>\n<meta name=\"twitter:creator\" content=\"@kinsta_dk\" \/>\n<meta name=\"twitter:site\" content=\"@kinsta_dk\" \/>\n<meta name=\"twitter:label1\" content=\"Skrevet af\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kumar Harsh\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimeret l\u00e6setid\" \/>\n\t<meta name=\"twitter:data2\" content=\"51 minutter\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/\"},\"author\":{\"name\":\"Kumar Harsh\",\"@id\":\"https:\/\/kinsta.com\/dk\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9\"},\"headline\":\"En omfattende guide til JavaScript-designm\u00f8nstre\",\"datePublished\":\"2023-02-14T08:36:12+00:00\",\"dateModified\":\"2023-08-24T09:30:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/\"},\"wordCount\":6322,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/dk\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png\",\"inLanguage\":\"da-DK\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/\",\"url\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/\",\"name\":\"En omfattende guide til JavaScript-designm\u00f8nstre\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/dk\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png\",\"datePublished\":\"2023-02-14T08:36:12+00:00\",\"dateModified\":\"2023-08-24T09:30:14+00:00\",\"description\":\"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#breadcrumb\"},\"inLanguage\":\"da-DK\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"da-DK\",\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png\",\"contentUrl\":\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png\",\"width\":1460,\"height\":730},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/dk\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript tutorials\",\"item\":\"https:\/\/kinsta.com\/dk\/emner\/javascript-tutorials\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"En omfattende guide til JavaScript-designm\u00f8nstre\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/dk\/#website\",\"url\":\"https:\/\/kinsta.com\/dk\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Hurtig, sikker, premium hostingl\u00f8sninger\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/dk\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/dk\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"da-DK\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/dk\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/dk\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"da-DK\",\"@id\":\"https:\/\/kinsta.com\/dk\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/dk\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Kinsta-Danmark-122855885298660\/\",\"https:\/\/x.com\/kinsta_dk\",\"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\/dk\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9\",\"name\":\"Kumar Harsh\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"da-DK\",\"@id\":\"https:\/\/kinsta.com\/dk\/#\/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\/dk\/blog\/author\/kumarharsh\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"En omfattende guide til JavaScript-designm\u00f8nstre","description":"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.","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\/dk\/blog\/javascript-designmoenstre\/","og_locale":"da_DK","og_type":"article","og_title":"En omfattende guide til JavaScript-designm\u00f8nstre","og_description":"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.","og_url":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/Kinsta-Danmark-122855885298660\/","article_published_time":"2023-02-14T08:36:12+00:00","article_modified_time":"2023-08-24T09:30:14+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png","type":"image\/png"}],"author":"Kumar Harsh","twitter_card":"summary_large_image","twitter_description":"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.","twitter_image":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png","twitter_creator":"@kinsta_dk","twitter_site":"@kinsta_dk","twitter_misc":{"Skrevet af":"Kumar Harsh","Estimeret l\u00e6setid":"51 minutter"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/"},"author":{"name":"Kumar Harsh","@id":"https:\/\/kinsta.com\/dk\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9"},"headline":"En omfattende guide til JavaScript-designm\u00f8nstre","datePublished":"2023-02-14T08:36:12+00:00","dateModified":"2023-08-24T09:30:14+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/"},"wordCount":6322,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/dk\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png","inLanguage":"da-DK","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/","url":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/","name":"En omfattende guide til JavaScript-designm\u00f8nstre","isPartOf":{"@id":"https:\/\/kinsta.com\/dk\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png","datePublished":"2023-02-14T08:36:12+00:00","dateModified":"2023-08-24T09:30:14+00:00","description":"Der er masser af JavaScript-designm\u00f8nstre, der kan spare dig for masser af tid og kr\u00e6fter. L\u00e6r om disse genanvendelige l\u00f8sninger i dette indl\u00e6g.","breadcrumb":{"@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#breadcrumb"},"inLanguage":"da-DK","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/"]}]},{"@type":"ImageObject","inLanguage":"da-DK","@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#primaryimage","url":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png","contentUrl":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/02\/javascript-design-patterns.png","width":1460,"height":730},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/dk\/blog\/javascript-designmoenstre\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/dk\/"},{"@type":"ListItem","position":2,"name":"JavaScript tutorials","item":"https:\/\/kinsta.com\/dk\/emner\/javascript-tutorials\/"},{"@type":"ListItem","position":3,"name":"En omfattende guide til JavaScript-designm\u00f8nstre"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/dk\/#website","url":"https:\/\/kinsta.com\/dk\/","name":"Kinsta\u00ae","description":"Hurtig, sikker, premium hostingl\u00f8sninger","publisher":{"@id":"https:\/\/kinsta.com\/dk\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/dk\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"da-DK"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/dk\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/dk\/","logo":{"@type":"ImageObject","inLanguage":"da-DK","@id":"https:\/\/kinsta.com\/dk\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/dk\/wp-content\/uploads\/sites\/12\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/dk\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Kinsta-Danmark-122855885298660\/","https:\/\/x.com\/kinsta_dk","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\/dk\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9","name":"Kumar Harsh","image":{"@type":"ImageObject","inLanguage":"da-DK","@id":"https:\/\/kinsta.com\/dk\/#\/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\/dk\/blog\/author\/kumarharsh\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/posts\/48667","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/users\/238"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/comments?post=48667"}],"version-history":[{"count":6,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/posts\/48667\/revisions"}],"predecessor-version":[{"id":49322,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/posts\/48667\/revisions\/49322"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/it"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/pt"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/fr"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/de"},{"embeddable":true,"hreflang":"ja","title":"Japanese","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/jp"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/nl"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/es"},{"embeddable":true,"hreflang":"sv","title":"Swedish","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/se"},{"embeddable":true,"hreflang":"da","title":"Danish","href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/translations\/dk"},{"href":"https:\/\/kinsta.com\/dk\/wp-json\/kinsta\/v1\/posts\/48667\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/media\/48668"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/media?parent=48667"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/tags?post=48667"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/dk\/wp-json\/wp\/v2\/topic?post=48667"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}