{"id":62918,"date":"2023-02-14T09:30:13","date_gmt":"2023-02-14T08:30:13","guid":{"rendered":"https:\/\/kinsta.com\/es\/?p=62918&#038;preview=true&#038;preview_id=62918"},"modified":"2025-01-17T14:25:23","modified_gmt":"2025-01-17T13:25:23","slug":"patrones-de-diseno-javascript","status":"publish","type":"post","link":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/","title":{"rendered":"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript"},"content":{"rendered":"<p>Al crear aplicaciones <a href=\"https:\/\/kinsta.com\/es\/blog\/que-es-javascript\/\">JavaScript<\/a>, puedes encontrarte con situaciones en las que necesites crear objetos de una forma determinada y predefinida, o reutilizar una clase com\u00fan modific\u00e1ndola o adapt\u00e1ndola a m\u00faltiples casos de uso.<\/p>\n<p>Por supuesto, no es conveniente resolver estos problemas una y otra vez.<\/p>\n<p>Aqu\u00ed es donde los patrones de dise\u00f1o de JavaScript vienen a tu rescate.<\/p>\n<p>Los patrones de dise\u00f1o de JavaScript te proporcionan una forma estructurada y repetible de abordar los problemas m\u00e1s frecuentes en el desarrollo de JavaScript.<\/p>\n<p>En esta gu\u00eda veremos qu\u00e9 son los patrones de dise\u00f1o de JavaScript y c\u00f3mo utilizarlos en tus aplicaciones JavaScript.<\/p>\n<div><\/div><kinsta-auto-toc heading=\"Table of Contents\" exclude=\"last\" list-style=\"arrow\" selector=\"h2\" count-number=\"-1\"><\/kinsta-auto-toc>\n<h2>\u00bfQu\u00e9 Es un Patr\u00f3n de Dise\u00f1o de JavaScript?<\/h2>\n<p>Los patrones de dise\u00f1o de JavaScript son plantillas de soluciones repetibles para problemas frecuentes en el desarrollo de aplicaciones JavaScript.<\/p>\n<p>La idea es sencilla: Los programadores de todo el mundo, desde los inicios del desarrollo, se han enfrentado a conjuntos de problemas recurrentes al <a href=\"https:\/\/kinsta.com\/es\/blog\/desarrollador-de-aplicaciones\/\">desarrollar aplicaciones<\/a>. Con el tiempo, algunos desarrolladores decidieron documentar formas probadas de abordar estos problemas para que otros pudieran consultar las soluciones con facilidad.<\/p>\n<p>A medida que m\u00e1s y m\u00e1s desarrolladores optaron por utilizar estas soluciones y reconocieron su eficacia para resolver sus problemas, se aceptaron como una forma est\u00e1ndar de resolver problemas y recibieron el nombre de \u00abpatrones de dise\u00f1o\u00bb<\/p>\n<p>A medida que se comprend\u00eda mejor la importancia de los patrones de dise\u00f1o, \u00e9stos se fueron desarrollando y estandarizando. En la actualidad, la mayor\u00eda de los patrones de dise\u00f1o modernos tienen una estructura definida, est\u00e1n organizados en varias categor\u00edas y se ense\u00f1an en las titulaciones relacionadas con la inform\u00e1tica como temas independientes.<\/p>\n<h2>Tipos de Patrones de Dise\u00f1o de JavaScript<\/h2>\n<p>Estas son algunas de las clasificaciones m\u00e1s populares de los patrones de dise\u00f1o de JavaScript.<\/p>\n<h3>Creacionales<\/h3>\n<p>Los patrones de dise\u00f1o creacionales son los que ayudan a resolver problemas relacionados con la creaci\u00f3n y gesti\u00f3n de nuevas instancias de objetos en JavaScript. Puede ser tan sencillo como limitar una clase a tener un solo objeto o tan complejo como definir un intrincado m\u00e9todo de selecci\u00f3n y adici\u00f3n manual de cada caracter\u00edstica en un objeto de JavaScript.<\/p>\n<p>Algunos ejemplos de patrones de dise\u00f1o de creaci\u00f3n son Singleton, Factory, Abstract Factory y Builder, entre otros.<\/p>\n<h3>Estructurales<\/h3>\n<p>Los patrones de dise\u00f1o estructurales son los que ayudan a resolver problemas relacionados con la gesti\u00f3n de la estructura (o esquema) de los objetos JavaScript. Estos problemas pueden incluir la creaci\u00f3n de una relaci\u00f3n entre dos objetos distintos o la abstracci\u00f3n de algunas caracter\u00edsticas de un objeto para usuarios espec\u00edficos.<\/p>\n<p>Algunos ejemplos de patrones de dise\u00f1o estructural son Adapter, Bridge, Composite, and Facade.<\/p>\n<h3>Conductuales<\/h3>\n<p>Los patrones de dise\u00f1o conductuales son los que ayudan a resolver problemas sobre c\u00f3mo se pasa el control (y la responsabilidad) entre varios objetos. Estos problemas podr\u00edan implicar controlar el acceso a una lista enlazada o establecer una \u00fanica entidad que pueda controlar el acceso a varios tipos de objetos.<\/p>\n<p>Algunos ejemplos de patrones de dise\u00f1o conductuales son Command, Iterator, Memento, y Observer.<\/p>\n<h3>Concurrencia<\/h3>\n<p>Los patrones de dise\u00f1o de concurrencia son los que ayudan a resolver problemas relacionados con el multihilo y la multitarea. Estos problemas pueden implicar el mantenimiento de un objeto activo entre m\u00faltiples objetos disponibles o el manejo de m\u00faltiples eventos suministrados a un sistema mediante la demultiplexaci\u00f3n de la entrada entrante y su manejo pieza a pieza.<\/p>\n<p>Algunos ejemplos de patrones de dise\u00f1o de concurrencia son active object, nuclear react, y scheduler.<\/p>\n<h3>Arquitect\u00f3nicos<\/h3>\n<p>Los patrones de dise\u00f1o arquitect\u00f3nico son los que ayudan a resolver problemas relacionados con el <a href=\"https:\/\/kinsta.com\/es\/blog\/arquitectura-aplicaciones-web\/\">dise\u00f1o de software<\/a> en sentido amplio. Por lo general, est\u00e1n relacionados con la forma de dise\u00f1ar tu sistema y garantizar una alta disponibilidad, mitigar los riesgos y <a href=\"https:\/\/kinsta.com\/es\/blog\/monitoreo-rendimiento-aplicaciones\/\">evitar los cuellos de botella en el rendimiento<\/a>.<\/p>\n<p>Dos ejemplos de patrones de dise\u00f1o arquitect\u00f3nico son MVC y MVVM.<\/p>\n<h2>Elementos de un Patr\u00f3n de Dise\u00f1o<\/h2>\n<p>Casi todos los patrones de dise\u00f1o pueden desglosarse en un conjunto de cuatro componentes importantes. \u00c9stos son:<\/p>\n<ul>\n<li><strong>Nombre del patr\u00f3n<\/strong>: Se utiliza para identificar un patr\u00f3n de dise\u00f1o mientras te comunicas con otros usuarios. Algunos ejemplos son \u00absingleton\u00bb, \u00abprototype\u00bb, etc.<\/li>\n<li><strong>Problema<\/strong>: Describe el objetivo del patr\u00f3n de dise\u00f1o. Es una peque\u00f1a descripci\u00f3n del problema que el patr\u00f3n de dise\u00f1o intenta resolver. Incluso puede incluir un escenario de ejemplo para explicar mejor el problema. Tambi\u00e9n puede contener una lista de condiciones que deben cumplirse para que un patr\u00f3n de dise\u00f1o resuelva completamente el problema subyacente.<\/li>\n<li><strong>Soluci\u00f3n<\/strong>: Es la soluci\u00f3n al problema en cuesti\u00f3n, formada por elementos como clases, m\u00e9todos, interfaces, etc. Es donde reside el grueso de un patr\u00f3n de dise\u00f1o \u2014 implica relaciones, responsabilidades y colaboradores de varios elementos que est\u00e1n claramente definidos.<\/li>\n<li><strong>Resultados<\/strong>: Se trata de un an\u00e1lisis de lo bien que el patr\u00f3n fue capaz de resolver el problema. Se discuten aspectos como el uso de espacio y tiempo, junto con enfoques alternativos para resolver el mismo problema.<\/li>\n<\/ul>\n<p>Si quieres saber m\u00e1s sobre los patrones de dise\u00f1o y sus inicios, la MSU tiene un <a href=\"https:\/\/www.cse.msu.edu\/~cse870\/Lectures\/SS2005\/08-design-patterns.ppt\">sucinto material de estudio<\/a> que puedes consultar.<\/p>\n<h2>\u00bfPor Qu\u00e9 Deber\u00edas Utilizar Patrones de Dise\u00f1o?<\/h2>\n<p>Hay m\u00faltiples razones por las que deber\u00edas utilizar patrones de dise\u00f1o:<\/p>\n<ul>\n<li><strong>Est\u00e1n probados y comprobados<\/strong>: Con un patr\u00f3n de dise\u00f1o, tienes una soluci\u00f3n probada y comprobada para tu problema (siempre que el patr\u00f3n de dise\u00f1o se ajuste a la descripci\u00f3n de tu problema). No tienes que perder el tiempo buscando soluciones alternativas, y puedes estar seguro de que tienes una soluci\u00f3n que se ocupa de la optimizaci\u00f3n b\u00e1sica del rendimiento por ti.<\/li>\n<li><strong>Son f\u00e1ciles de entender<\/strong>: Los patrones de dise\u00f1o est\u00e1n pensados para ser peque\u00f1os, sencillos y f\u00e1ciles de entender. No necesitas ser un programador especializado que trabaje en un sector espec\u00edfico durante d\u00e9cadas para entender qu\u00e9 patr\u00f3n de dise\u00f1o utilizar. Son deliberadamente gen\u00e9ricos (no se limitan a ning\u00fan lenguaje de programaci\u00f3n concreto) y puede entenderlos cualquiera que tenga suficientes habilidades para resolver problemas. Esto tambi\u00e9n ayuda cuando hay un cambio de manos en el equipo t\u00e9cnico: Un fragmento de c\u00f3digo que se basa en un patr\u00f3n de dise\u00f1o es m\u00e1s f\u00e1cil de entender para cualquier nuevo desarrollador de software.<\/li>\n<\/ul>\n<ul>\n<li><strong>Son sencillos de implementar<\/strong>: La mayor\u00eda de los patrones de dise\u00f1o son muy sencillos, como ver\u00e1s m\u00e1s adelante en nuestro art\u00edculo. No necesitas conocer m\u00faltiples <a href=\"https:\/\/kinsta.com\/es\/blog\/programacion-orientada-objetos-python\/\">conceptos de programaci\u00f3n<\/a> para implementarlos en tu c\u00f3digo.<\/li>\n<\/ul>\n<ul>\n<li><strong>Proponen una arquitectura del c\u00f3digo f\u00e1cilmente reutilizable<\/strong>: La reutilizaci\u00f3n y la <a href=\"https:\/\/kinsta.com\/es\/blog\/mejores-practicas-html\/\">limpieza del c\u00f3digo se fomentan<\/a> mucho en la industria tecnol\u00f3gica, y los patrones de dise\u00f1o pueden ayudarte a conseguirlo. Puesto que estos patrones son una forma est\u00e1ndar de resolver problemas, sus dise\u00f1adores se han preocupado de garantizar que la arquitectura de la aplicaci\u00f3n que los engloba siga siendo reutilizable, flexible y compatible con la mayor\u00eda de las formas de escribir c\u00f3digo.<\/li>\n<\/ul>\n<ul>\n<li><strong>Ahorran tiempo y tama\u00f1o de la aplicaci\u00f3n<\/strong>: Una de las mayores ventajas de confiar en un conjunto est\u00e1ndar de soluciones es que te ayudar\u00e1n a ahorrar tiempo al implementarlas. Es muy probable que todo tu equipo de desarrollo conozca bien los patrones de dise\u00f1o, por lo que les resultar\u00e1 m\u00e1s f\u00e1cil <a href=\"https:\/\/kinsta.com\/es\/blog\/microsoft-teams-contra-slack\/\">planificar, comunicar y colaborar<\/a> al implementarlos. Las soluciones probadas y comprobadas significan que hay muchas posibilidades de que no acabes perdiendo recursos o dando un rodeo mientras construyes alguna funci\u00f3n, lo que te ahorrar\u00e1 tiempo y espacio. Adem\u00e1s, la mayor\u00eda de los <a href=\"https:\/\/kinsta.com\/es\/blog\/mejor-lenguaje-de-programacion-para-aprender\/\">lenguajes de programaci\u00f3n<\/a> te proporcionan bibliotecas de plantillas est\u00e1ndar que ya implementan algunos patrones de dise\u00f1o comunes, como Iterator y Observer.<\/li>\n<\/ul>\n<h2>Los 20 Mejores Patrones de Dise\u00f1o de JavaScript que Debes Dominar<\/h2>\n<p>Ahora que ya sabes de qu\u00e9 est\u00e1 hecho un patr\u00f3n de dise\u00f1o y por qu\u00e9 los necesitas, vamos a profundizar en c\u00f3mo se pueden implementar en una <a href=\"https:\/\/kinsta.com\/es\/blog\/node-js-aplicaciones\/\">aplicaci\u00f3n JavaScript<\/a> algunos de los patrones de dise\u00f1o de JavaScript m\u00e1s utilizados.<\/p>\n<h3>Creacionales<\/h3>\n<p>Empecemos el debate con algunos patrones de dise\u00f1o creacionales fundamentales y f\u00e1ciles de aprender.<\/p>\n<h4>1. Singleton<\/h4>\n<p>El patr\u00f3n Singleton es uno de los patrones de dise\u00f1o m\u00e1s utilizados en la industria del desarrollo de software. El problema que pretende resolver es mantener una \u00fanica instancia de una clase. Esto puede resultar \u00fatil cuando se instancian objetos que consumen muchos recursos, como los manejadores de bases de datos.<\/p>\n<p>A continuaci\u00f3n te explicamos c\u00f3mo puedes implementarlo en 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>Aunque cumple bien su prop\u00f3sito, el patr\u00f3n Singleton es conocido porque dificulta la depuraci\u00f3n, ya que enmascara las dependencias y controla el acceso a la inicializaci\u00f3n o destrucci\u00f3n de las instancias de una clase.<\/p>\n<h4>2. Factory<\/h4>\n<p>El m\u00e9todo Factory tambi\u00e9n es uno de los patrones de dise\u00f1o m\u00e1s populares. El problema que pretende resolver el m\u00e9todo Factory es crear objetos sin utilizar el constructor convencional. En su lugar, toma la configuraci\u00f3n (o descripci\u00f3n) del objeto que deseas y devuelve el objeto reci\u00e9n creado.<\/p>\n<p>Aqu\u00ed te explicamos c\u00f3mo puedes implementarlo en 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>El patr\u00f3n de dise\u00f1o Factory controla c\u00f3mo se crear\u00e1n los objetos y te proporciona una forma r\u00e1pida de crear nuevos objetos, as\u00ed como una interfaz uniforme que define las propiedades que tendr\u00e1n tus objetos. Puedes a\u00f1adir tantas razas de perros como quieras, siempre que los m\u00e9todos y propiedades expuestos por los tipos de razas sigan siendo los mismos, funcionar\u00e1n a la perfecci\u00f3n.<\/p>\n<p>Sin embargo, ten en cuenta que el patr\u00f3n Factory a menudo puede dar lugar a un gran n\u00famero de clases dif\u00edciles de gestionar.<\/p>\n<h4>3. Abstract Factory<\/h4>\n<p>El m\u00e9todo Abstract Factory sube el nivel del m\u00e9todo Factory al hacer que haya \u00abfactories\u00bb abstractas y, por tanto, sustituibles sin que el entorno de llamada conozca la factory exacta utilizada o su funcionamiento interno. El entorno de llamada s\u00f3lo sabe que todas las \u00abfactories\u00bb tienen un conjunto de m\u00e9todos comunes a los que puede llamar para realizar la acci\u00f3n de instanciaci\u00f3n.<\/p>\n<p>As\u00ed es como puede implementarse utilizando el ejemplo anterior:<\/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>El patr\u00f3n Abstract Factory te facilita el intercambio de factories concretas, y ayuda a promover la uniformidad entre las factories y los productos creados. Sin embargo, puede resultar dif\u00edcil introducir nuevos tipos de productos, ya que tendr\u00edas que hacer cambios en varias clases para dar cabida a nuevos m\u00e9todos\/propiedades.<\/p>\n<h4>4. Builder<\/h4>\n<p>El patr\u00f3n Builder es uno de los patrones de dise\u00f1o creacionales de JavaScript m\u00e1s complejos y flexibles. Te permite construir una a una las caracter\u00edsticas de tu producto, proporcion\u00e1ndote un control total sobre c\u00f3mo se construye tu objeto, al tiempo que abstrae los detalles internos.<\/p>\n<p>En el intrincado ejemplo de abajo, ver\u00e1s el patr\u00f3n de dise\u00f1o Builder en acci\u00f3n con Director para ayudar a hacer \u00a1Pizzas!<\/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>Puede conectar el Builder con un Director, , como muestra la clase <code>PizzaShop<\/code> en el ejemplo anterior, para predefinir un conjunto de pasos a seguir cada vez que construyas una variante est\u00e1ndar de tu producto, es decir, una receta espec\u00edfica para tus pizzas.<\/p>\n<p>El \u00fanico problema de este patr\u00f3n de dise\u00f1o es que es bastante complejo de configurar y mantener. Sin embargo, a\u00f1adir nuevas funciones de esta forma es m\u00e1s sencillo que con el m\u00e9todo Factory.<\/p>\n<h4>5. Prototype<\/h4>\n<p>El patr\u00f3n de dise\u00f1o Prototype es una forma r\u00e1pida y sencilla de crear nuevos objetos a partir de objetos existentes, clon\u00e1ndolos.<\/p>\n<p>Primero se crea un objeto prototipo, que puede clonarse varias veces para crear nuevos objetos. Resulta \u00fatil cuando instanciar directamente un objeto es una operaci\u00f3n que consume m\u00e1s recursos que crear una copia de uno existente.<\/p>\n<p>En el siguiente ejemplo, ver\u00e1s c\u00f3mo puedes utilizar el patr\u00f3n Prototype para crear nuevos documentos basados en un documento plantilla establecido:<\/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>El m\u00e9todo Prototype funciona muy bien para los casos en que una gran parte de tus objetos comparten los mismos valores, o cuando crear un objeto nuevo por completo es bastante costoso. Sin embargo, parece una exageraci\u00f3n en casos en los que no necesitas m\u00e1s que unas pocas instancias de la clase.<\/p>\n<h3>Estructurales<\/h3>\n<p>Los patrones de dise\u00f1o estructurales te ayudan a organizar tu l\u00f3gica de negocio proporcion\u00e1ndote formas probadas de estructurar tus clases. Existe una gran variedad de patrones de dise\u00f1o estructural que se adaptan a casos de uso \u00fanicos.<\/p>\n<h4>6. Adapter<\/h4>\n<p>Un problema habitual al crear aplicaciones es permitir la colaboraci\u00f3n entre clases incompatibles.<\/p>\n<p>Un buen ejemplo para entender esto es mantener la compatibilidad hacia atr\u00e1s. Si escribes una nueva versi\u00f3n de una clase, naturalmente querr\u00e1s que sea f\u00e1cilmente utilizable en todos los lugares donde funcionaba la versi\u00f3n antigua. Sin embargo, si haces cambios de ruptura, como eliminar o actualizar m\u00e9todos que eran cruciales para el funcionamiento de la versi\u00f3n antigua, puedes acabar con una clase que necesite que se actualicen todos sus clientes para poder ejecutarse.<\/p>\n<p>En estos casos, el patr\u00f3n de dise\u00f1o Adapter puede ser de ayuda.<\/p>\n<p>El patr\u00f3n de dise\u00f1o Adapter te proporciona una abstracci\u00f3n que sirve de puente entre los m\u00e9todos y propiedades de la nueva clase y los m\u00e9todos y propiedades de la antigua. Tiene la misma interfaz que la clase antigua, pero contiene l\u00f3gica para asignar los m\u00e9todos antiguos a los nuevos para ejecutar operaciones similares. Esto es similar a c\u00f3mo una toma de corriente act\u00faa como adaptador entre un enchufe de estilo estadounidense y un enchufe de estilo europeo.<\/p>\n<p>Aqu\u00ed tienes un ejemplo:<\/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>El principal problema de este patr\u00f3n de dise\u00f1o es que a\u00f1ade complejidad a tu c\u00f3digo fuente. Ya ten\u00edas que mantener dos clases diferentes, y ahora tienes otra clase\u00a0 \u2014 la Adapter \u2014 que mantener.<\/p>\n<h4>7. Bridge<\/h4>\n<p>Ampliando el patr\u00f3n Adapter, el patr\u00f3n de dise\u00f1o Bridge proporciona tanto a la clase como al cliente interfaces independientes para que ambos puedan funcionar incluso en casos de interfaces nativas incompatibles.<\/p>\n<p>Ayuda a desarrollar una interfaz muy poco acoplada entre los dos tipos de objetos. Tambi\u00e9n ayuda a mejorar la extensibilidad de las interfaces y sus implementaciones para obtener la m\u00e1xima flexibilidad.<\/p>\n<p>A continuaci\u00f3n te explicamos c\u00f3mo puedes utilizarlo:<\/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>Como ya habr\u00e1s adivinado, el patr\u00f3n Bridge aumenta enormemente la complejidad de la base de c\u00f3digo. Adem\u00e1s, la mayor\u00eda de las interfaces suelen acabar con una sola implementaci\u00f3n en los casos de uso del mundo real, por lo que realmente no te beneficias mucho de la reutilizaci\u00f3n del c\u00f3digo.<\/p>\n<h4>8. Composite<\/h4>\n<p>El patr\u00f3n de dise\u00f1o Composite te ayuda a estructurar y gestionar f\u00e1cilmente objetos y entidades similares. La idea b\u00e1sica del patr\u00f3n Composite es que los objetos y sus contenedores l\u00f3gicos pueden representarse utilizando una \u00fanica clase abstracta (que puede almacenar datos\/m\u00e9todos relacionados con el objeto y referencias a s\u00ed misma para el contenedor).<\/p>\n<p>Tiene m\u00e1s sentido utilizar el patr\u00f3n Composite cuando tu modelo de datos se asemeja a una estructura de \u00e1rbol. Sin embargo, no debes intentar convertir un modelo de datos no arb\u00f3reo en un modelo de datos arb\u00f3reo s\u00f3lo por utilizar el patr\u00f3n Composite, ya que hacerlo a menudo puede restarle mucha flexibilidad.<\/p>\n<p>En el siguiente ejemplo, ver\u00e1s c\u00f3mo puedes utilizar el patr\u00f3n de dise\u00f1o Composite para construir un sistema de empaquetado para productos de comercio electr\u00f3nico que tambi\u00e9n pueda calcular el valor total del pedido por paquete:<\/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>El mayor inconveniente de utilizar el patr\u00f3n Composite es que los cambios en las interfaces de los componentes pueden ser muy complicados en el futuro. Dise\u00f1ar las interfaces requiere tiempo y esfuerzo, y la naturaleza arborescente del modelo de datos puede dificultar mucho la introducci\u00f3n de cambios a tu antojo.<\/p>\n<h4>9. Decorator<\/h4>\n<p>El patr\u00f3n Decorator te ayuda a a\u00f1adir nuevas funciones a los objetos existentes simplemente envolvi\u00e9ndolos dentro de un nuevo objeto. Es similar a c\u00f3mo puedes envolver una caja de regalo ya envuelta con papel de regalo nuevo tantas veces como quieras: Cada envoltorio te permite a\u00f1adir tantas funciones como quieras, as\u00ed que es muy flexible.<\/p>\n<p>Desde un punto de vista t\u00e9cnico, no hay herencia, por lo que hay mayor libertad a la hora de dise\u00f1ar la l\u00f3gica empresarial.<\/p>\n<p>En el ejemplo siguiente, ver\u00e1s c\u00f3mo el patr\u00f3n Decorator ayuda a a\u00f1adir m\u00e1s funciones a una clase est\u00e1ndar de <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>Las desventajas de este patr\u00f3n incluyen la alta complejidad del c\u00f3digo, ya que no existe un patr\u00f3n est\u00e1ndar definido para a\u00f1adir nuevas funciones mediante decoradores. Podr\u00edas acabar con un mont\u00f3n de decoradores no uniformes y\/o similares al final de tu ciclo de vida de desarrollo de software.<\/p>\n<p>Si no tienes cuidado al dise\u00f1ar los decoradores, puedes acabar dise\u00f1ando unos decoradores que dependan l\u00f3gicamente de otros. Si esto no se resuelve, eliminar o reestructurar los decoradores m\u00e1s adelante puede causar estragos en la estabilidad de tu aplicaci\u00f3n.<\/p>\n<h4>10. Facade<\/h4>\n<p>Al construir la mayor\u00eda de las aplicaciones del mundo real, la l\u00f3gica de negocio suele resultar bastante compleja cuando terminas. Puede que acabes con m\u00faltiples objetos y m\u00e9todos implicados en la ejecuci\u00f3n de las operaciones principales de tu aplicaci\u00f3n. Hacer un seguimiento de sus inicializaciones, dependencias, el orden correcto de ejecuci\u00f3n de los m\u00e9todos, etc., puede ser bastante complicado y propenso a errores si no se hace correctamente.<\/p>\n<p>El patr\u00f3n de dise\u00f1o Facade te ayuda a crear una abstracci\u00f3n entre el entorno que invoca las operaciones mencionadas y los objetos y m\u00e9todos implicados en la realizaci\u00f3n de esas operaciones. Esta abstracci\u00f3n alberga la l\u00f3gica para inicializar los objetos, rastrear sus dependencias y otras actividades importantes. El entorno de llamada no tiene informaci\u00f3n sobre c\u00f3mo se ejecuta una operaci\u00f3n. Puedes actualizar libremente la l\u00f3gica sin realizar ning\u00fan cambio de ruptura en el cliente llamante.<\/p>\n<p>A continuaci\u00f3n te explicamos c\u00f3mo utilizarlo en una aplicaci\u00f3n:<\/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>Una desventaja de utilizar el patr\u00f3n Facade es que a\u00f1ade una capa adicional de abstracci\u00f3n entre tu l\u00f3gica de negocio y el cliente, lo que requiere un mantenimiento adicional. En la mayor\u00eda de los casos, esto aumenta la complejidad general del c\u00f3digo base.<\/p>\n<p>Adem\u00e1s, la clase <code>Facade<\/code> se convierte en una dependencia obligatoria para el funcionamiento de tu aplicaci\u00f3n, lo que significa que cualquier error en la clase <code>Facade<\/code> repercute directamente en el funcionamiento de tu aplicaci\u00f3n.<\/p>\n<h4>11. Flyweight<\/h4>\n<p>El patr\u00f3n Flyweight te ayuda a resolver problemas que implican objetos con componentes que se repiten de forma eficiente en memoria, ayud\u00e1ndote a reutilizar los componentes comunes de tu conjunto de objetos. Esto ayuda a reducir la carga en la memoria y tambi\u00e9n da lugar a tiempos de ejecuci\u00f3n m\u00e1s r\u00e1pidos.<\/p>\n<p>En el siguiente ejemplo, se almacena una frase larga en la memoria utilizando el patr\u00f3n de dise\u00f1o Flyweight. En lugar de almacenar cada car\u00e1cter a medida que se produce, el programa identifica el conjunto de caracteres distintos que se han utilizado para escribir el p\u00e1rrafo y sus tipos (n\u00famero o alfabeto) y construye flyweights reutilizables para cada car\u00e1cter que contienen detalles sobre qu\u00e9 car\u00e1cter y tipo se almacenan.<\/p>\n<p>Despu\u00e9s, la matriz principal s\u00f3lo almacena una lista de referencias a estos pesos volantes en el orden en que aparecen en la frase, en lugar de almacenar una instancia del objeto car\u00e1cter cada vez que aparece.<\/p>\n<p>Esto reduce a la mitad la memoria que ocupa la frase. Ten en cuenta que \u00e9sta es una explicaci\u00f3n muy b\u00e1sica de c\u00f3mo almacenan el texto los procesadores de texto.<\/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>Como ya te habr\u00e1s dado cuenta, el patr\u00f3n Flyweight a\u00f1ade complejidad al dise\u00f1o de tu software al no ser especialmente intuitivo. As\u00ed que, si ahorrar memoria no es una preocupaci\u00f3n acuciante para tu aplicaci\u00f3n, la complejidad a\u00f1adida de Flyweight puede hacer m\u00e1s mal que bien.<\/p>\n<p>Adem\u00e1s, los Flyweight intercambian memoria por eficiencia de procesamiento, as\u00ed que si te faltan ciclos de CPU, Flyweight no es una buena soluci\u00f3n para ti.<\/p>\n<h4>12. Proxy<\/h4>\n<p>El patr\u00f3n Proxy te ayuda a sustituir un objeto por otro. En otras palabras, los objetos proxy pueden ocupar el lugar de objetos reales (de los que son un proxy) y controlar el acceso al objeto. Estos objetos proxy pueden utilizarse para realizar algunas acciones antes o despu\u00e9s de pasar una solicitud de invocaci\u00f3n al objeto real.<\/p>\n<p>En el ejemplo siguiente, ver\u00e1s c\u00f3mo se controla el acceso a una instancia de base de datos mediante un proxy que realiza algunas comprobaciones b\u00e1sicas de validaci\u00f3n de las solicitudes antes de permitir su paso:<\/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>Este patr\u00f3n de dise\u00f1o se utiliza habitualmente en todo el sector y ayuda a implementar f\u00e1cilmente operaciones previas y posteriores a la ejecuci\u00f3n. Sin embargo, como cualquier otro patr\u00f3n de dise\u00f1o, tambi\u00e9n a\u00f1ade complejidad a tu c\u00f3digo base, as\u00ed que intenta no utilizarlo si no lo necesitas realmente.<\/p>\n<p>Tambi\u00e9n deber\u00e1s tener en cuenta que, dado que interviene un objeto adicional al realizar llamadas a tu objeto principal, puede haber cierta latencia debida a las operaciones de procesamiento a\u00f1adidas. Optimizar el rendimiento de tu objeto principal ahora tambi\u00e9n implica optimizar el rendimiento de los m\u00e9todos de tu proxy.<\/p>\n<h3>Conductuales<\/h3>\n<p>Los patrones de dise\u00f1o conductuales te ayudan a resolver problemas sobre c\u00f3mo interact\u00faan los objetos entre s\u00ed. Esto puede implicar compartir o pasar responsabilidad\/control entre objetos para completar operaciones de conjunto. Tambi\u00e9n puede implicar pasar\/compartir datos entre varios objetos de la forma m\u00e1s eficiente posible.<\/p>\n<h4>13. Chain of Responsibility<\/h4>\n<p>El patr\u00f3n Chain of Responsibility es uno de los patrones de dise\u00f1o de comportamiento m\u00e1s sencillos. Resulta \u00fatil cuando dise\u00f1as la l\u00f3gica de operaciones que pueden ser gestionadas por varios controladores.<\/p>\n<p>De forma similar a c\u00f3mo funciona el escalado de incidencias en los equipos de soporte, el control pasa a trav\u00e9s de una cadena de manejadores, y el manejador responsable de realizar la acci\u00f3n completa la operaci\u00f3n. Este patr\u00f3n de dise\u00f1o se utiliza a menudo en el dise\u00f1o de IU, donde varias capas de componentes pueden gestionar un evento de entrada del usuario, como un toque o un deslizamiento.<\/p>\n<p>A continuaci\u00f3n ver\u00e1s un ejemplo de escalado de una queja utilizando el patr\u00f3n Chain of Responsibility. La reclamaci\u00f3n ser\u00e1 tratada por los gestores en funci\u00f3n de su gravedad:<\/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>El problema obvio de este dise\u00f1o es que es lineal, por lo que puede haber cierta latencia en la gesti\u00f3n de una operaci\u00f3n cuando un gran n\u00famero de gestores est\u00e1n encadenados entre s\u00ed.<\/p>\n<p>Hacer un seguimiento de todos los manipuladores puede ser otro punto doloroso, ya que puede volverse bastante desordenado a partir de un cierto n\u00famero de manipuladores. La depuraci\u00f3n es otra pesadilla, ya que cada solicitud puede terminar en un manejador diferente, lo que te dificulta estandarizar el <a href=\"https:\/\/kinsta.com\/es\/blog\/node-debug\/\">proceso de registro y depuraci\u00f3n<\/a>.<\/p>\n<h4>14. Iterator<\/h4>\n<p>El patr\u00f3n Iterator es bastante sencillo y se utiliza con mucha frecuencia en casi todos los lenguajes modernos orientados a objetos. Si te encuentras ante la tarea de recorrer una lista de objetos que no son todos del mismo tipo, los m\u00e9todos de iteraci\u00f3n normales, como un bucle for, pueden resultar bastante complicados \u2014 sobre todo si tambi\u00e9n est\u00e1s escribiendo l\u00f3gica de negocio dentro de ellos.<\/p>\n<p>El patr\u00f3n Iterator puede ayudarte a aislar la l\u00f3gica de iteraci\u00f3n y procesamiento de tus listas de la l\u00f3gica de negocio principal.<\/p>\n<p>A continuaci\u00f3n te mostramos c\u00f3mo puedes utilizarlo en una lista bastante b\u00e1sica con varios tipos de elementos:<\/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>No hace falta decir que este patr\u00f3n puede ser innecesariamente complejo para listas sin m\u00faltiples tipos de elementos. Adem\u00e1s, si hay demasiados tipos de elementos en una lista, tambi\u00e9n puede resultar dif\u00edcil de gestionar.<\/p>\n<p>La clave est\u00e1 en identificar si realmente necesitas un iterador en funci\u00f3n de tu lista y de sus posibilidades de cambio en el futuro. Adem\u00e1s, el patr\u00f3n Iterator s\u00f3lo es \u00fatil en listas, y las listas a veces pueden limitarte a su modo lineal de acceso. Otras estructuras de datos pueden proporcionarte a veces mayores ventajas de rendimiento.<\/p>\n<h4>15. Mediator<\/h4>\n<p>El dise\u00f1o de tu aplicaci\u00f3n a veces puede requerir que juegues con un gran n\u00famero de objetos distintos que albergan diversos tipos de l\u00f3gica empresarial y que a menudo dependen unos de otros. Manejar las dependencias a veces puede resultar complicado, ya que necesitas hacer un seguimiento de c\u00f3mo estos objetos intercambian datos y control entre ellos.<\/p>\n<p>El patr\u00f3n de dise\u00f1o Mediator pretende ayudarte a resolver este problema aislando la l\u00f3gica de interacci\u00f3n de estos objetos en un objeto independiente por s\u00ed mismo.<\/p>\n<p>Este objeto separado se conoce como mediador, y es el responsable de que tus clases de nivel inferior realicen el trabajo. Tu cliente o el entorno de llamada tambi\u00e9n interactuar\u00e1n con el mediador en lugar de con las clases de nivel inferior.<\/p>\n<p>Aqu\u00ed tienes un ejemplo del patr\u00f3n de dise\u00f1o mediator en acci\u00f3n:<\/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>Aunque mediator proporciona al dise\u00f1o de tu aplicaci\u00f3n desacoplamiento y una gran flexibilidad, al fin y al cabo es otra clase que debes mantener. Debes evaluar si tu dise\u00f1o puede beneficiarse realmente de un mediador antes de escribir uno, para no acabar a\u00f1adiendo una complejidad innecesaria a tu base de c\u00f3digo.<\/p>\n<p>Tambi\u00e9n es importante tener en cuenta que, aunque la clase mediator no contenga ninguna l\u00f3gica de negocio directa, sigue conteniendo mucho c\u00f3digo que es crucial para el funcionamiento de tu aplicaci\u00f3n y, por tanto, puede volverse r\u00e1pidamente bastante compleja.<\/p>\n<h4>16. Memento<\/h4>\n<p>Versionar objetos es otro problema com\u00fan al que te enfrentar\u00e1s cuando desarrolles aplicaciones. Hay muchos casos de uso en los que necesitas mantener el historial de un objeto, facilitar las reversiones y, a veces, incluso revertir esas reversiones. Escribir la l\u00f3gica para este tipo de aplicaciones puede ser dif\u00edcil.<\/p>\n<p>El patr\u00f3n de dise\u00f1o Memento est\u00e1 pensado para resolver este problema f\u00e1cilmente.<\/p>\n<p>Un memento se considera una instant\u00e1nea de un objeto en un momento determinado. El patr\u00f3n de dise\u00f1o Memento utiliza estos mementos para conservar instant\u00e1neas del objeto a medida que se modifica con el tiempo. Cuando necesites volver a una versi\u00f3n anterior, s\u00f3lo tienes que recuperar el memento correspondiente.<\/p>\n<p>A continuaci\u00f3n te explicamos c\u00f3mo puedes implementarlo en una aplicaci\u00f3n de procesamiento de texto:<\/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>Aunque el patr\u00f3n de dise\u00f1o Memento es una gran soluci\u00f3n para gestionar el historial de un objeto, puede llegar a consumir muchos recursos. Dado que cada memento es casi una copia del objeto, puede inflar la memoria de tu aplicaci\u00f3n muy r\u00e1pidamente si no se utiliza con moderaci\u00f3n.<\/p>\n<p>Con un gran n\u00famero de objetos, la gesti\u00f3n de su ciclo de vida tambi\u00e9n puede ser una tarea bastante tediosa. Adem\u00e1s de todo esto, las clases <code>Originator<\/code> y <code>Caretaker<\/code> suelen estar muy acopladas, lo que aumenta la complejidad de tu c\u00f3digo base.<\/p>\n<h4>17. Observer<\/h4>\n<p>El patr\u00f3n Observer proporciona una soluci\u00f3n alternativa al problema de la interacci\u00f3n multiobjeto (visto anteriormente en el patr\u00f3n Mediator).<\/p>\n<p>En lugar de permitir que cada objeto se comunique entre s\u00ed a trav\u00e9s de un mediador designado, el patr\u00f3n Observer les permite observarse mutuamente. Los objetos est\u00e1n dise\u00f1ados para emitir eventos cuando intentan enviar datos o control, y otros objetos que est\u00e1n \u00abescuchando\u00bb estos eventos pueden entonces recibirlos e interactuar bas\u00e1ndose en su contenido.<\/p>\n<p>Aqu\u00ed tienes una demostraci\u00f3n sencilla de c\u00f3mo enviar newsletters a varias personas a trav\u00e9s del patr\u00f3n Observer:<\/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>Aunque el patr\u00f3n Observer es una forma h\u00e1bil de pasar el control y los datos, es m\u00e1s adecuado para situaciones en las que hay un gran n\u00famero de emisores y receptores que interact\u00faan entre s\u00ed a trav\u00e9s de un n\u00famero limitado de conexiones. Si todos los objetos establecieran conexiones uno a uno, perder\u00edas la ventaja que obtienes publicando y suscribi\u00e9ndote a eventos, ya que siempre habr\u00e1 un \u00fanico suscriptor por cada publicador (cuando hubiera sido mejor gestionarlo mediante una l\u00ednea directa de comunicaci\u00f3n entre ellos).<\/p>\n<p>Adem\u00e1s, el patr\u00f3n de dise\u00f1o Observer puede provocar problemas de rendimiento si los eventos de suscripci\u00f3n no se gestionan adecuadamente. Si un objeto contin\u00faa suscribi\u00e9ndose a otro objeto incluso cuando no lo necesita, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lapsed_listener_problem\">no podr\u00e1 optar a la recogida de basura<\/a> y aumentar\u00e1 el consumo de memoria de la aplicaci\u00f3n.<\/p>\n<h4>18. State<\/h4>\n<p>El patr\u00f3n de dise\u00f1o State es uno de los patrones de dise\u00f1o m\u00e1s utilizados en la industria del desarrollo de software. Los <a href=\"https:\/\/kinsta.com\/es\/blog\/bibliotecas-javascript\/\">frameworks de JavaScript<\/a> m\u00e1s populares, como <a href=\"https:\/\/reactjs.org\/docs\/state-and-lifecycle.html\">React<\/a> y <a href=\"https:\/\/medium.com\/olricdigital\/introduction-to-state-management-in-angular-v2-ef6f5144bade\">Angular<\/a>, se basan en gran medida en el patr\u00f3n State para gestionar los datos y el comportamiento de la aplicaci\u00f3n en funci\u00f3n de esos datos.<\/p>\n<p>En pocas palabras, el patr\u00f3n de dise\u00f1o State es \u00fatil en situaciones en las que puedes definir estados definitivos de una entidad (que podr\u00eda ser un componente, una p\u00e1gina, una app o una m\u00e1quina), y la entidad tiene una reacci\u00f3n predefinida al cambio de estado.<\/p>\n<p>Digamos que est\u00e1s intentando construir un proceso de solicitud de pr\u00e9stamo. Cada paso del proceso de solicitud puede definirse como un estado.<\/p>\n<p>Aunque el cliente suele ver una peque\u00f1a lista de estados simplificados de su solicitud (pendiente, en revisi\u00f3n, aceptada y rechazada), puede haber otros pasos implicados internamente. En cada uno de estos pasos, la solicitud se asignar\u00e1 a una persona distinta y puede tener requisitos \u00fanicos.<\/p>\n<p>El sistema est\u00e1 dise\u00f1ado de tal forma que al final de la tramitaci\u00f3n en un estado, \u00e9ste se actualiza al siguiente de la fila, y se inicia el siguiente conjunto de pasos pertinente.<\/p>\n<p>A continuaci\u00f3n se explica c\u00f3mo crear un sistema de gesti\u00f3n de tareas utilizando el patr\u00f3n de dise\u00f1o State:<\/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>Aunque el patr\u00f3n State hace un gran trabajo segregando pasos en un proceso, puede llegar a ser extremadamente dif\u00edcil de mantener en grandes aplicaciones que tienen m\u00faltiples estados.<\/p>\n<p>Adem\u00e1s, si el dise\u00f1o de tu proceso permite algo m\u00e1s que moverse linealmente a trav\u00e9s de todos los estados, te ver\u00e1s obligado a escribir y mantener m\u00e1s c\u00f3digo, ya que cada transici\u00f3n de estado debe gestionarse por separado.<\/p>\n<h4>19. Strategy<\/h4>\n<p>Tambi\u00e9n conocido como patr\u00f3n Policy, el patr\u00f3n Strategy pretende ayudarte a encapsular e intercambiar libremente clases utilizando una interfaz com\u00fan. Esto ayuda a mantener un acoplamiento d\u00e9bil entre el cliente y las clases y te permite a\u00f1adir tantas implementaciones como desees.<\/p>\n<p>Se sabe que el patr\u00f3n Strategy ayuda enormemente en situaciones en las que se necesita la misma operaci\u00f3n utilizando diferentes m\u00e9todos\/algoritmos, o cuando hay que sustituir bloques de conmutaci\u00f3n masivos por c\u00f3digo m\u00e1s amigable.<\/p>\n<p>Aqu\u00ed tienes un ejemplo del patr\u00f3n Strategy:<\/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>El patr\u00f3n Strategy es estupendo cuando se trata de introducir nuevas variaciones de una entidad sin cambiar mucho a los clientes. Sin embargo, puede parecer exagerado si s\u00f3lo tienes que implementar algunas variaciones.<\/p>\n<p>Adem\u00e1s, la encapsulaci\u00f3n elimina los detalles m\u00e1s sutiles sobre la l\u00f3gica interna de cada variante, por lo que tu cliente desconoce c\u00f3mo se va a comportar una variante.<\/p>\n<h4>20. Visitor<\/h4>\n<p>El patr\u00f3n Visitor pretende ayudarte a que tu c\u00f3digo sea extensible.<\/p>\n<p>La idea es proporcionar un m\u00e9todo en la clase que permita a los objetos de otras clases realizar cambios en los objetos de la clase actual con facilidad. Los otros objetos <em>visitan<\/em> el objeto actual (tambi\u00e9n llamado objeto lugar), o la clase actual <em>acepta <\/em>los objetos visitantes, y el objeto lugar gestiona adecuadamente la visita de cada objeto externo.<\/p>\n<p>A continuaci\u00f3n te explicamos c\u00f3mo puedes utilizarlo:<\/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>El \u00fanico defecto de este dise\u00f1o es que cada clase de visitante debe actualizarse cada vez que se a\u00f1ade o modifica un nuevo lugar. En los casos en que existan varios visitantes y objetos de lugar juntos, esto puede ser dif\u00edcil de mantener.<\/p>\n<p>Aparte de eso, el m\u00e9todo funciona muy bien para mejorar la funcionalidad de las clases de forma din\u00e1mica.<\/p>\n<h2>Mejores Pr\u00e1cticas para Implementar Patrones de Dise\u00f1o<\/h2>\n<p>Ahora que has visto los patrones de dise\u00f1o m\u00e1s comunes en JavaScript, aqu\u00ed tienes algunos consejos que debes tener en cuenta al implementarlos.<\/p>\n<h3>Pon Especial Cuidado en Entender si un Patr\u00f3n se Ajusta a la Soluci\u00f3n<\/h3>\n<p>Este consejo debe aplicarse antes de implementar un patr\u00f3n de dise\u00f1o en tu c\u00f3digo fuente. Aunque pueda parecer que un patr\u00f3n de dise\u00f1o es el fin de todas tus preocupaciones, t\u00f3mate un momento para analizar cr\u00edticamente si eso es cierto.<\/p>\n<p>Hay muchos patrones que resuelven el mismo problema, pero adoptan enfoques diferentes y tienen consecuencias distintas. As\u00ed que tu criterio para seleccionar un patr\u00f3n de dise\u00f1o no deber\u00eda ser \u00fanicamente si resuelve tu problema o no \u2014 tambi\u00e9n deber\u00eda ser lo bien que resuelve tu problema y si hay alg\u00fan otro patr\u00f3n que pueda presentar una soluci\u00f3n m\u00e1s eficiente.<\/p>\n<h3>Comprende los Costes de Implantaci\u00f3n de un Patr\u00f3n Antes de Empezar<\/h3>\n<p>Aunque los patrones de dise\u00f1o parecen ser la mejor soluci\u00f3n para todos los <a href=\"https:\/\/kinsta.com\/es\/blog\/errores-en-javascript\/\">problemas de ingenier\u00eda<\/a>, no deber\u00edas lanzarte a implementarlos en tu c\u00f3digo fuente de inmediato.<\/p>\n<p>Al juzgar las consecuencias de implementar una soluci\u00f3n, tambi\u00e9n debes tener en cuenta tu propia situaci\u00f3n. \u00bfTienes un gran equipo de desarrolladores de software que son expertos en comprender y mantener patrones de dise\u00f1o? \u00bfO eres un fundador en fase inicial con un equipo de desarrollo m\u00ednimo que busca lanzar un MVP r\u00e1pido de su producto? Si respondes afirmativamente a la \u00faltima pregunta, puede que los patrones de dise\u00f1o no sean la forma de desarrollo m\u00e1s \u00f3ptima para ti.<\/p>\n<p>Los patrones de dise\u00f1o no conducen a una gran reutilizaci\u00f3n del c\u00f3digo a menos que se planifiquen en una fase muy temprana del dise\u00f1o de la aplicaci\u00f3n. Utilizar patrones de dise\u00f1o al azar en varias fases puede dar lugar a una arquitectura de aplicaci\u00f3n innecesariamente compleja que tendr\u00edas que pasar semanas simplificando.<\/p>\n<p>La eficacia de un patr\u00f3n de dise\u00f1o no puede juzgarse mediante ninguna forma de prueba. Son la <a href=\"https:\/\/kinsta.com\/es\/blog\/herramientas-de-revision-de-codigo\/\">experiencia y la introspecci\u00f3n de tu equipo<\/a> las que te permitir\u00e1n saber si funcionan. Si tienes el tiempo y los recursos para dedicar a estos aspectos, s\u00f3lo entonces los patrones de dise\u00f1o resolver\u00e1n realmente tus problemas.<\/p>\n<h3>No Conviertas Cada Soluci\u00f3n en un Patr\u00f3n<\/h3>\n<p>Otra regla a tener en cuenta es abstenerse de intentar convertir cada peque\u00f1o binomio problema-soluci\u00f3n en un patr\u00f3n de dise\u00f1o y utilizarlo siempre que veas espacio para ello.<\/p>\n<p>Aunque es bueno identificar soluciones est\u00e1ndar y tenerlas en mente cuando te encuentres con problemas similares, hay muchas posibilidades de que el nuevo problema que has encontrado no se ajuste exactamente a la misma descripci\u00f3n que un problema anterior. En tal caso, podr\u00edas acabar aplicando una soluci\u00f3n sub\u00f3ptima y desperdiciando recursos.<\/p>\n<p>Los patrones de dise\u00f1o est\u00e1n establecidos hoy como ejemplos principales de binomios problema-soluci\u00f3n porque han sido probados por cientos y miles de programadores a lo largo del tiempo y se han generalizado tanto como ha sido posible. Si intentas replicar ese esfuerzo simplemente mirando un mont\u00f3n de problemas y soluciones y llam\u00e1ndolos similares, podr\u00edas acabar haciendo mucho m\u00e1s da\u00f1o a tu c\u00f3digo del que esperabas.<\/p>\n<h2>\u00bfCu\u00e1ndo Debes Utilizar Patrones de Dise\u00f1o?<\/h2>\n<p>En resumen, aqu\u00ed tienes algunas pistas a tener en cuenta para utilizar patrones de dise\u00f1o. No todas se aplican al desarrollo de todas las aplicaciones, pero deber\u00edan darte una buena idea de lo que debes tener en cuenta cuando pienses en utilizar patrones de dise\u00f1o:<\/p>\n<ul>\n<li>Tienes un s\u00f3lido equipo interno de desarrolladores que entiende bien los patrones de dise\u00f1o.<\/li>\n<li>Sigues un modelo de SDLC que permite discusiones en profundidad sobre la arquitectura de tu aplicaci\u00f3n, y los patrones de dise\u00f1o han surgido en esas discusiones.<\/li>\n<li>El mismo conjunto de problemas ha surgido varias veces en tus discusiones sobre dise\u00f1o, y conoces el patr\u00f3n de dise\u00f1o que se ajustar\u00e1 al caso.<\/li>\n<li>Has intentado resolver una variaci\u00f3n menor de tu problema de forma independiente con el patr\u00f3n de dise\u00f1o.<\/li>\n<li>Con el patr\u00f3n de dise\u00f1o establecido, tu c\u00f3digo no parece excesivamente complejo.<\/li>\n<\/ul>\n<p>Si un patr\u00f3n de dise\u00f1o resuelve tu problema <em>y<\/em> te ayuda a escribir un c\u00f3digo sencillo, reutilizable, modular, d\u00e9bilmente acoplado y sin \u00abolor a c\u00f3digo\u00bb, puede que sea el camino correcto.<\/p>\n<p>Otro buen consejo a tener en cuenta es evitar que todo gire en torno a los patrones de dise\u00f1o. Los patrones de dise\u00f1o est\u00e1n pensados para ayudarte a resolver problemas. No son leyes que debas acatar ni reglas que debas seguir estrictamente. Las reglas y leyes fundamentales siguen siendo las mismas: mant\u00e9n tu c\u00f3digo limpio, sencillo, legible y escalable. Si un patr\u00f3n de dise\u00f1o te ayuda a hacer eso a la vez que resuelve tu problema, deber\u00edas estar bien con \u00e9l.<\/p>\n<h2>Resumen<\/h2>\n<p>Los patrones de dise\u00f1o de JavaScript son una forma maravillosa de abordar problemas a los que se han enfrentado muchos programadores a lo largo del tiempo. Presentan soluciones probadas y comprobadas que se esfuerzan por mantener tu c\u00f3digo limpio y d\u00e9bilmente acoplado.<\/p>\n<p>Hoy en d\u00eda, hay <a href=\"https:\/\/sourcemaking.com\/design-patterns-and-tips\">cientos de patrones de dise\u00f1o<\/a> disponibles que resolver\u00e1n casi cualquier problema que encuentres al crear aplicaciones. Sin embargo, no todos los patrones de dise\u00f1o resolver\u00e1n <em>realmente<\/em> tu problema siempre.<\/p>\n\n<p>Al igual que cualquier <a href=\"https:\/\/kinsta.com\/es\/blog\/practicas-de-react\/\">otra convenci\u00f3n de programaci\u00f3n<\/a>, los patrones de dise\u00f1o deben tomarse como sugerencias para resolver problemas. No son leyes que deban seguirse siempre, y si los tratas como leyes, podr\u00edas acabar haciendo mucho da\u00f1o a tus aplicaciones.<\/p>\n<p>Una vez que tu aplicaci\u00f3n est\u00e9 terminada, necesitar\u00e1s un lugar donde alojarla \u2014 y las <a href=\"https:\/\/sevalla.com\/application-hosting\/\">soluciones de Alojamiento de Aplicaciones de Kinsta<\/a> son las m\u00e1s r\u00e1pidas, fiables y seguras. S\u00f3lo tienes que iniciar sesi\u00f3n en tu <a href=\"https:\/\/kinsta.com\/es\/mykinsta\/\">cuenta MyKinsta<\/a> (el panel de control administrativo personalizado de Kinsta), conectarte a tu <a href=\"https:\/\/kinsta.com\/es\/blog\/que-es-github\/\">repositorio de GitHub<\/a>, \u00a1y lanzarla! Adem\u00e1s, s\u00f3lo se te cobrar\u00e1 por los recursos que utilice tu aplicaci\u00f3n.<\/p>\n<p>\u00bfCu\u00e1les son los patrones de dise\u00f1o que utilizas habitualmente en tu trabajo de programaci\u00f3n de software? \u00bfO hay alg\u00fan patr\u00f3n que se nos haya pasado en la lista? \u00a1H\u00e1znoslo saber en los comentarios de abajo!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Al crear aplicaciones JavaScript, puedes encontrarte con situaciones en las que necesites crear objetos de una forma determinada y predefinida, o reutilizar una clase com\u00fan modific\u00e1ndola &#8230;<\/p>\n","protected":false},"author":238,"featured_media":62919,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[],"topic":[1297],"class_list":["post-62918","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","topic-tutoriales-javascript"],"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>Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript<\/title>\n<meta name=\"description\" content=\"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.\" \/>\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\/es\/blog\/patrones-de-diseno-javascript\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript\" \/>\n<meta property=\"og:description\" content=\"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kinsta.es\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-14T08:30:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-01-17T13:25:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/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=\"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png\" \/>\n<meta name=\"twitter:creator\" content=\"@Kinsta_ES\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_ES\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kumar Harsh\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"53 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/\"},\"author\":{\"name\":\"Kumar Harsh\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9\"},\"headline\":\"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript\",\"datePublished\":\"2023-02-14T08:30:13+00:00\",\"dateModified\":\"2025-01-17T13:25:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/\"},\"wordCount\":6850,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/es\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png\",\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/\",\"url\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/\",\"name\":\"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/es\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png\",\"datePublished\":\"2023-02-14T08:30:13+00:00\",\"dateModified\":\"2025-01-17T13:25:23+00:00\",\"description\":\"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png\",\"contentUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png\",\"width\":1460,\"height\":730},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/es\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tutoriales JavaScript\",\"item\":\"https:\/\/kinsta.com\/es\/secciones\/tutoriales-javascript\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/es\/#website\",\"url\":\"https:\/\/kinsta.com\/es\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Soluciones de alojamiento premium, r\u00e1pidas y seguras\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/es\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/es\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/es\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/es\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/kinsta.es\/\",\"https:\/\/x.com\/Kinsta_ES\",\"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\/es\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9\",\"name\":\"Kumar Harsh\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/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\/es\/blog\/author\/kumarharsh\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript","description":"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.","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\/es\/blog\/patrones-de-diseno-javascript\/","og_locale":"es_ES","og_type":"article","og_title":"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript","og_description":"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.","og_url":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/kinsta.es\/","article_published_time":"2023-02-14T08:30:13+00:00","article_modified_time":"2025-01-17T13:25:23+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png","type":"image\/png"}],"author":"Kumar Harsh","twitter_card":"summary_large_image","twitter_description":"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.","twitter_image":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png","twitter_creator":"@Kinsta_ES","twitter_site":"@Kinsta_ES","twitter_misc":{"Escrito por":"Kumar Harsh","Tiempo de lectura":"53 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/"},"author":{"name":"Kumar Harsh","@id":"https:\/\/kinsta.com\/es\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9"},"headline":"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript","datePublished":"2023-02-14T08:30:13+00:00","dateModified":"2025-01-17T13:25:23+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/"},"wordCount":6850,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/es\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png","inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/","url":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/","name":"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript","isPartOf":{"@id":"https:\/\/kinsta.com\/es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png","datePublished":"2023-02-14T08:30:13+00:00","dateModified":"2025-01-17T13:25:23+00:00","description":"Existen muchos patrones de dise\u00f1o de JavaScript que pueden ahorrarte mucho tiempo y esfuerzo. Conoce estas soluciones reutilizables en este post.","breadcrumb":{"@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#primaryimage","url":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png","contentUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/02\/javascript-design-patterns.png","width":1460,"height":730},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/es\/blog\/patrones-de-diseno-javascript\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/es\/"},{"@type":"ListItem","position":2,"name":"Tutoriales JavaScript","item":"https:\/\/kinsta.com\/es\/secciones\/tutoriales-javascript\/"},{"@type":"ListItem","position":3,"name":"Gu\u00eda Exhaustiva de Patrones de Dise\u00f1o de JavaScript"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/es\/#website","url":"https:\/\/kinsta.com\/es\/","name":"Kinsta\u00ae","description":"Soluciones de alojamiento premium, r\u00e1pidas y seguras","publisher":{"@id":"https:\/\/kinsta.com\/es\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/es\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/es\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kinsta.es\/","https:\/\/x.com\/Kinsta_ES","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\/es\/#\/schema\/person\/3a80efffa9cbb0333cc9c22b754415d9","name":"Kumar Harsh","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/kinsta.com\/es\/#\/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\/es\/blog\/author\/kumarharsh\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts\/62918","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/users\/238"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/comments?post=62918"}],"version-history":[{"count":14,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts\/62918\/revisions"}],"predecessor-version":[{"id":63643,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts\/62918\/revisions\/63643"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/it"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/pt"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/fr"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/de"},{"embeddable":true,"hreflang":"ja","title":"Japanese","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/jp"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/nl"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/es"},{"embeddable":true,"hreflang":"sv","title":"Swedish","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/se"},{"embeddable":true,"hreflang":"da","title":"Danish","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/translations\/dk"},{"href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/62918\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/media\/62919"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/media?parent=62918"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/tags?post=62918"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/topic?post=62918"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}