Top Banner
1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.7 Tabla de contenido Introducción Conocimientos previos Reseña histórica Buenas prácticas Principios de diseño Patrones de diseño Requisitos Estructura Categorías Catálogo de patrones Antipatrones El lenguaje Javascript Elección del lenguaje Javascript y programación orientada a objetos Patrones creacionales Abstract Factory Builder Factory Prototype Singleton Patrones estructurales Adapter Bridge Composite Decorator Facade Flyweight Proxy Patrones de comportamiento Chain of responsibility Command Iterator Mediator Memento Observer Template method Otros Patrones 1
66

Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Jul 12, 2019

Download

Documents

hoangdan
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

1.1

1.1.1

1.1.2

1.1.3

1.1.4

1.2

1.2.1

1.2.2

1.2.3

1.2.4

1.2.5

1.3

1.3.1

1.3.2

1.4

1.4.1

1.4.2

1.4.3

1.4.4

1.4.5

1.5

1.5.1

1.5.2

1.5.3

1.5.4

1.5.5

1.5.6

1.5.7

1.6

1.6.1

1.6.2

1.6.3

1.6.4

1.6.5

1.6.6

1.6.7

1.7

Tabla de contenidoIntroducción

Conocimientos previos

Reseña histórica

Buenas prácticas

Principios de diseño

Patrones de diseño

Requisitos

Estructura

Categorías

Catálogo de patrones

Antipatrones

El lenguaje Javascript

Elección del lenguaje

Javascript y programación orientada a objetos

Patrones creacionales

Abstract Factory

Builder

Factory

Prototype

Singleton

Patrones estructurales

Adapter

Bridge

Composite

Decorator

Facade

Flyweight

Proxy

Patrones de comportamiento

Chain of responsibility

Command

Iterator

Mediator

Memento

Observer

Template method

Otros Patrones

1

Page 2: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

1.7.1

1.7.2

Module Pattern

Revealing module

2

Page 3: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

IntroducciónEl diseño, desarrollo y mantenimiento de aplicaciones software puede ser un gran desafío intelectual, sobre todoen sistemas de alta complejidad o criticidad. Un mal diseño puede provocar:

Sobrecostes.Ejecución del proyecto fuera de plazo.Software ineficiente.Software de mala calidad y frágil.Software que no cumple los requisitos.Software dificil de mantener.Catástrofes humanas .

Por ello, en lugar de reinventar la rueda durante la etapa de diseño de cada sistema, es preferible reutilizarsoluciones ampliamente conocidas y validadas, también llamadas "patrones de diseño" en el ámbito de laarquitectura de software. Éstos ofrecen "Una descripción detallada de una solución a un problema recurrentedentro de un contexto" . De forma simplificada, pueden ser vistos como "recetas" que describen cómo resolverproblemas en diferentes situaciones.

Este documento recopila y documenta, usando javascript como lenguaje de programación, la aplicación de lospatrones de diseño más utilizados en la actualidad.

. Relación de fallos software catastróficos (https://en.wikipedia.org/wiki/List_of_software_bugs) ↩

. Alexander, Christopher; Ishikawa, Sara; Silverstein, Murray; Jacobson, Max; Fiksdahl-King, Ingrid; Angel,Shlomo (1977). A Pattern Language: Towns, Buildings, Construction. New York: Oxford University Press. ISBN978-0-19-501919-3. ↩

1

2

1

2

3

Page 4: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Conocimientos previosPara la correcta compresión de los conceptos que se introducen en este documento se requiere que el lectordisponga de nociones de programación orientada a objetos, así como del lenguaje Javascript en su versiónECMAScript 5 .

De no ser así, se recomienda como paso previo la adquisición de dichos conocimientos. Internet ofrecenumerosos recursos gratuitos al respecto, entre los que se encuentran:

Programación orientada a objetos (Wikipedia):(https://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos)Javascript syntax (Wikipedia): (https://en.wikipedia.org/wiki/JavaScript_syntax)Introducción a Javascript (librosweb): (https://librosweb.es/libro/javascript/)Guía de Javascript (Mozilla Developer Network - MDN):(https://developer.mozilla.org/es/docs/Web/JavaScript/Guide)Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications and libraries. PacktPublishing (2008). Stoyan Stefanov. ISBN 9781847194145

. ECMAScript Languaje Specification (http://www.ecma-international.org/ecma-262/5.1/) ↩

1

1

4

Page 5: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Reseña históricaLas dificultades para escribir programas comprensibles, mantenibles y libres de defectos fueron expuestas porprimera vez en 1968 en la "NATO Software Engineering Conference" bajo el patrocinio de la OTAN , donde seacuñó el término "crisis del software" para referenciar la problemática identificada. Posteriormente, EdsgerDijkstra empleó el mismo término en su artículo "The Humble Programmer" .

La Ingeniería de software surge como respuesta a esta situación, tratando de aplicar ingeniería al proceso dediseño, desarrollo, implementación, pruebas y mantenimiento del software. Dentro de este enfoque sistemático ydisciplinado de desarrollo software aparece la aplicación de los patrones de diseño, aunque no obtienen unarelevancia significativa hasta la publicación del libro "Design Patterns" .

. Artículos de la conferencia (http://homepages.cs.ncl.ac.uk/brian.randell/NATO/) ↩

. Dijkstra, Edger. The Humble Programmer (http://www.cs.utexas.edu/users/EWD/ewd03xx/EWD340.PDF) ↩

. Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns:Elements ofReusable Object-Oriented software. Addison-Wesley. ISBN 0-201-63361-2. ↩

1

2

3

1

2

3

5

Page 6: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Buenas prácticas de codificaciónComo paso previo a la aplicación de patrones de diseño, el lector debería conocer algunas buenas prácticasgenéricas de codificación. Aunque existe multitud de bibliografía al respecto, resalta especialmente el libro "CleanCode. A Handbook of Agile Software-Craftsmanship" de Robert C. Martin (editorial Prentice Hall). En él se definenalgunas pautas que permiten generar código fuente de mayor calidad (lo que el autor denomina como "códigolimpio"). De aplicación inmediata son:

Usar nombres expresivos y fáciles de leer en clases/funciones/variablesLas funciones deben ser cortas, hacer una única cosa y mantenerse dentro del mismo nival de abstracción.Además, no deben provocar efectos secundarios en la aplicación.Una función debe tener cuanto menos argumentos, mejor.Los comentarios no pueden maquillar un mal código. Tampoco debe contradecirlo.ES mejor provocar excepciones que devolver códigos de error

6

Page 7: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Principios básicos de diseñoAsociados a la Ingeniería de software, aparecen una serie de principios básicos de diseño que favorecen eldesarrollo de aplicaciones mantenibles y reutilizables. La lista es bastante extensa, por lo que sólo semencionarán aquellos de conocimiento popular.

Si desea obtener más información, puede recurrir al listado proporcionado por la wikipedia en el enlace List ofsoftware development philosophies

Principio KISS (Keep it simple, stupid!)

Establece que el diseño de un programa debe ser cuanto más sencillo, mejor, evitando complejidadesinnecesarias.

Principio DRY (Don't repeat yourself)

Propone no escribir código duplicado.

El código duplicado es propenso a errores y dificil de mantener, por lo que es mejor extraerlo y encapsularlo.

Principio YAGNI (You ain-t gonna need it)

Sugiere al programador no agregar funcionalidades a la aplicación/código a menos que estas sean realmentenecesarias, evitando la tentación de escribir código sólo porque se prevé su uso.

Principio de Hollywood (Don’t Call Us, We’ll Call You!)

Este principio hace referencia al eslogan de los directivos de Hollywood "No nos llames, nosotros te llamaremos".Pretende conseguir un menor acoplamiento entre los componentes de una aplicación a través de la inversión decontrol

Ley de Demeter (No hables con extraños)

También conocida como "Principio de Menor Conocimiento" también favorece el bajo acoplamiento entre cadaunidad a través de las siguientes pautas:

Cada unidad debe tener un conocimiento limitado sobre otras unidadesCAda unidad debe hablar solo a sus amigos inmediatos.

Principio SOLID

Introducido por Robert C. Martin, hace referencia a cinco principios de diseño :

(S)ingle responsability principle: Una clase sólo debe tener una única responsabilidad. Además, dicha clasedebe ser la única con esa responsabilidad(O)pen/close principle: Las entidades de software deben estar abiertas para su extensión, pero cerradas parasu modificación. Esto es, una entidad no debería modificar su comportamiento, únicamente ampliarlo (aexcepción de corrección de errores).(L)iskov substitution principle: Los objetos de un programa deberían ser reemplazables por instancias de sussubtipos. Como consecuencia, una clase derivada no debe modificar el comportamiento de la clase base.(I)nterface segregation principle: Muchas interfaces específicas son mejores que una de propósito general.Ninguna clase debería estar forzada a implementar un método que no requiere.

1

2

3

7

Page 8: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

(D)ependency inversion principle: Una clase debería depender de abstracciones, no de implementaciones.

. Ficha en FOLDOC (http://foldoc.org/KISS%20Principle) ↩

. Inversión de control. Martin Fowler (http://martinfowler.com/bliki/InversionOfControl.html) ↩

. Artículo de Robert C. Martin"UncleBob"(http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod) ↩

1

2

3

8

Page 9: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Patrones de diseñoLa RAE define el término patrón como "modelo que sirve de muestra para sacar otra cosa igual". En ingeniería desoftware, los patrones de diseño proporcionan:

Buenas soluciones de diseño validas para un problema recurrente en un contexto determinado.Código ampliamente verificado, reutilizable y mantenible.Un vocabulario común entre diseñadores software.

Debido a la importancia y trascendencia del libro "Design Patterns", cuyos autores son conocidos como GoF(Gang of Four), en los siguientes subapartados se emplearán las definiciones incluidas en el citado documento.

9

Page 10: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

RequisitosPara que una solución represente un patrón de diseño debe cumplir una serie de requisitos, a saber:

Debe ser capaz de resolver un problema particular.El problema debe ser recurrente.La solución a este problema no debe ser obvia.La solución debe describir una relación entre los elementos que la componen.El concepto descrito en la solución debe haber sido probado, validado y aceptado en la comunidad.

10

Page 11: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

EstructuraSegún GoF un patrón de diseño se describe a través de una plantilla que debe contener los siguientes elementos:

Nombre del patrón y clasificación: Nombre estándar.Propósito: Frase breve que responde a las cuestiones ¿Qué hace este patrón de diseño?¿En qué se basa?¿Cuál es el problema concreto de diseño que resuelve?Alias: Nombres alternativos.Motivación: Escenario que ilustra el problema de diseño y cómo el patrón resuelve el problema.Aplicabilidad: Situaciones en las que se puede aplicar el patrón de diseño. Ejemplos de malos diseños queel patrón puede resolver. Cómo reconocer dichas situaciones.Estructura: Representación gráfica de las clases que emplea el patrón (OMT/UML)Participantes: Clases y objetos participanptes en el patrón, junto con sus responsabilidadesColaboraciones: Colaboración entre participantes para llevar a cabo su responsabilidadConsecuencias: Descripción de consecución de objetivos. Ventajas e inconvenientes de usar el patrón.Implementación: Dificultades, trucos y técnicas que se deben tener en cuenta a la hora de aplicar el patrón.Cuestiones específicas del lenguaje.Código de ejemplo: Fragmentos de código que muestran implementaciones del patrón.Usos conocidos: Ejemplos de uso en sistemas reales.Patrones relacionados: Enumeración de otros patrones estrechamente relacionados. Dependencias ydiferencias.

11

Page 12: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

CategoríasGoF cataloga los patrones de diseños de acuerdo a dos criterios diferentes:

Propósito: Refleja qué hace un patrón:

De creación: Relacionados con los proceso de creación de objetos (cómo se obtienen y construyen)Estructural: Tratan con la composición entre clases u objetos (cómo se acoplan, relacionan, componen ycomunican un conjunto de clases/objetos)De comportamiento: Caracterizan el modo en que las clases y objetos interactúan y se reparten lasresponsabilidades.

Ámbito: Especifica si el patrón se aplica principalmente a la clase o a objetos.

De clases: se ocupan de las relaciones entre las clases y sus subclases. éstas relaciones seestablecen a través de la herencia, de modo que son relaciones estáticas.De objetos: Tratan con las relaciones entre objetos, que pueden cambiarse en tiempo de ejecución.

12

Page 13: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Catálogo de patronesEl siguiente cuadro resume los principales patrones agrupados según las categorías del apartado anterior.

Creacionales. Basados en el concepto de creación de objetos

Ámbitode

clases

FactoryMethod

Define una interfaz para crear un objeto, pero deja que sean las subclases quienes decidanqué clase instanciar. Permite que una clase delegue en sus subclases la creación de objetos.

ÁmbitodeObjetos

AbstractFactory

Proporciona una interfaz para crear familias de objetos relacionados o que dependen entre sí,sin especificar sus clases concretas.

Builder Separa la construcción de un objeto complejo de su representación, de forma aque el mismoproceso de construcción pueda crear diferentes representaciones.

Prototype Especifica los tipos de objetos a crear por medio de una instancia prototípica, y crea nuevosobjetos copiando de este prototipo.

Singleton Garantiza que una clase sólo tenga una instancia, y proporciona un punto de acceso global aella.

Estructurales. Basados en la idea de la construcción de bloques de objetos

Ámbito declases

Adapter Convierte la interfaz de una clase en otra distinta que es la que esperan los clientes. Permiteque cooperen clases que de otra manera no podrían por tener interfaces incompatibles.

Ámbito deObjetos

Bridge Desacopla una abstracción de su implementación, de manera que ambas puedan variar deforma independiente.

Composite Combina objetos en estructuras de árbol para representar jerarquías de parte-todo. Permiteque los clientes traten de manera uniforme a los objetos individuales y a los compuestos.

Decorator Añade dinámicamente nuevas responsabilidades a un objeto, proporcionando unaalternativa flexible a la herencia para extender la funcionalidad.

Facade Proporciona una interfaz unificada para un conjunto de interfaces de un subsistema. Defineuna interfaz de alto nivel que hace que el subsistema sea más facil de usar.

Flyweight Usa el compartimento para permitir un gran número de objetos de grano fino de formaeficiente.

Proxy Proporciona un sustituto o representante de otro objeto para controlar el acceso a éste.

De comportamiento. Basados en cómo interaccionan entre sí los objetos

13

Page 14: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Ámbito declases

Interpreter Dado un lenguaje, define una representación de su gramática junto con un intérprete queusa dicha representación par interpretar sentencias del lenguaje.

TemplateMethod

Define en una operación el esqueleto de un algoritmo, delegando en las subclasesalgunos de sus pasos. Permite que las subclases redefinan ciertos pasos del algoritmosin cambiar su estructura.

Ámbito deObjetos

Chain ofResponsibility

Evita acoplar el emisor de una petición a su receptor, al dar a más de un objeto laposibilidad de responder a la petición. Crea una cadena con los objetos receptores ypasa la petición a traves de la cadena hasta que ésta sea tratada por algún objeto.

CommandEncapsula una petición en un objeto, permitiendo así parametrizar a los clientes condistintas peticiones, encolar o llevar un registro de las peticiones y poder deshacer laoperación.

Iterator Proporciona un modo de acceder secuencialmente a los elementos de un objetoagregado sin exponer su representación interna.

MediatorDefine un objeto que encapsula cómo interactúan un conjunto de objetos. Promueve unbajo acoplamiento al evitgar que los objetos se refieran unos a otros explícitamente, ypermite variar la interacción entre ellos de forma independiente.

Memento Representa y externaliza el estado interno de un objeto sin violar la encapsulación, deforma que éste puede volver a dicho estado más tarde.

ObserverDefine una dependencia de uno-a-muchos entre objetos, de forma que cuando un objetocambie de estado se notifica y se actualizan automáticamente todos los objetos quedependen de él.

State Permite que un objeto modifique su comportamiento cada vez que cambie su estadointerno. Parecerá que cambia la clase del objeto.

StrategyDefine una familia de algoritmos, encapsula cada uno de ellos y los haceintercambiables. Permite que un algoritmo varía independientemente de los clientes quelo usan.

Visitor Representa una operación sobre los elementos de una estructura de objetos. Permitedefinir una nueva operación sin cambiar las clases de los elementos sobre los que opera

14

Page 15: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

AntipatronesAsí como los patrones de diseño representan buenas prácticas, los antipatrones simbolizan malas práxis.Agrupan aquellos patrones de diseño que provocan inexorablemente una mala solución al problema que tratan deresolver. Conocer los antipatrones de diseño es un factor clave para detectar y evitar soluciones desaconsejadas.

Aunque quedan fuera del alcance de este documento, se recomienda la lectura del siguiente material:

Catálogo de Antipatrones: (http://c2.com/cgi/wiki?AntiPatternsCatalog)Listado de Antipatrones más conocidos (Wikipedia): (https://en.wikipedia.org/wiki/Anti-pattern)[Browm et al 1998] Anti Patterns. Refactoring software, Architectures and Projects in Crisis. W.J. Brown, R.C.Malveau, H.W. “Skip” McCormick III, T. J. Mowbray. Wiley, 1998.

15

Page 16: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

El lenguaje JavascriptAunque el nombre del lenguaje sugiere similitudes con Java, poco o nada tiene que ver con éste. Javascript es unlenguaje de alto nivel, dinámico, no tipado, interpretado, basado en prototipos con funciones como ciudadanos deprimera clase (lo cual permite, además de la programación imperativa, el estilo de programación funcional).

. First-class functions Wikipedia (https://en.wikipedia.org/wiki/First-class_function) ↩

1

1

16

Page 17: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Elección del lenguajeExisten muchos argumentos para elegir Javascript como lenguaje de programación, pero tal vez el másimportante de todos sea su alcance. Junto con HTML y CSS, es una de las tres tecnologías básicas del WorldWide Web y está soportado por casi todos los navegadores del mundo sin necesidad de plug-ins, por lo quedesarrollar aplicaciones en Javascript facilita su distribución en cualquier ordenador o smartphone.

A ello se le suma la gran expansión que el lenguaje ha sufrido en el lado servidor, gracias a Node.js y al servidorNo-SQL MongoDB , permitiendo el desarrollo de aplicaciones cliente/servidor empleando un único lenguajecomún: Javascript. De hecho, existe todo un conjunto de de sistemas (conocido como MEAN Stack ) que facilitanel desarrollo integral de aplicaciones cliente/servidor.

. Página oficial de NodeJs (https://nodejs.org/en/) ↩

. Página oficial de MongoDB (https://www.mongodb.com/es) ↩

. MEAN Wikipedia (https://es.wikipedia.org/wiki/MEAN) ↩

12

3

1

2

3

17

Page 18: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Javascript y programación orientada a objetosLos patrones de diseños descritos en el libro "Design Pattern" sustentan su definición en la programaciónorientada a objetos usando el modelo basado en clases. Javascript, en cambio, es un lenguaje de programaciónorientada a objetos basado en prototipos en el que no existen el concepto de clases, por lo que laimplementación de los diferentes patrones de diseño requiere de una adaptación a las características propias dellenguaje.

No obstante, Javascript permite emular la mayoría de las características propias de una clase. Gracias a la nociónde prototipos y al azúcar sintáctico que proporciona el lenguaje, es posible implementar los conceptos de clase,constructor, propiedades, métodos, herencia, polimorfismo, encapsulamiento y abstracción.

Los siguientes subapartados, extraídos de MDN muestran una metodología para emplear los conceptosanteriores en Javascript, aunque existen multiples alternativas.

La clase

Javascript permite usar funciones para definir una clase. Por ejemplo:

function Persona() { }

Puede encontrar métodos alternativos para describir una clase en el blog de Stoyan Stefanov(http://www.phpied.com/3-ways-to-define-a-javascript-class/)

El Objeto

Para crear un objeto concreto a partir de la clase persona, se utilizará el operador "new":

function Persona() { }

var persona1= new Persona();

El constructor

El constructor es el método de la clase que se llama durante la instanciación del objeto. En javascript, la funciónPersona() se emplea a la vez como definición de la clase y constructor.

Las propiedades del objeto

Las propiedades son variables contenidas en la clase. Cada instancia de la clase (objeto) tiene dichaspropiedades. La palabra reservada "this" permite crear variables propias de la clase. El acceso externo apropiedades de la clase se realiza a través del operador punto '.'.

function Persona(nombre){ this.nombre = nombre; // Propiedad 'nombre'}

var persona1 = new Persona("Rocío"); /// Nuevo objeto persona1console.log(persona1.nombre); // Muestra 'Rocío'

Los métodos

1

2

3

18

Page 19: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Los métodos se definen de la misma forma similar a las propiedades. El acceso externo a un método de la clasese realiza a través del operador '.', pero agregando () al final del nombre del método para ejecutarlo.

// Definición de la clase Personafunction Persona(nombre){ // Definición de la propiedad nombre this.nombre = nombre;}

// Definición del método saludar()Persona.prototype.saludar = function() { console.log('Hola, soy ' + this.nombre);};

// Creación del objeto persona1var persona1 = new Persona("Rocío");

// Llamada al método saludar() del objeto persona1persona1.saludar(); // Muestra "Hola, soy Rocío" en la consola

Herencia

Mediante la herencia se consigue crear una subclase como una versión especializada de otra clase base. EnJavascript la herencia se logra mediante la asignación de una instancia de la clase primaria a la clase secundariay la posterior especialización.

19

Page 20: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Definimos la clase padre 'Persona'function Persona(nombre) { // Propiedad de la clase padre this.nombre = nombre; }

// Método de la clase padrePersona.prototype.saludar = function() { console.log("Hola, Soy" + this.nombre);};

// Definimos la clase hija 'Estudiante'function Estudiante(nombre, asignatura) { // Llamamos al constructor de la clase padre Persona.call(this, nombre);

// Propiedad de la clase hija this.asignatura = asignatura; };

// Hacemos que la clase Estudiante herede de la clase Persona// https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/createEstudiante.prototype = Object.create(Persona.prototype);

// Establecemos la propiedad "constructor" para referenciar a EstudianteEstudiante.prototype.constructor = Estudiante;

// Agregamos el método caminar() a la clase hijaEstudiante.prototype.caminar = function() { console.log("¡Estoy caminando!");};

// Ejemplos de usovar estudiante1 = new Estudiante("Rocío", "Filosofía");estudiante1.saludar(); // muestra "Hola, Soy Rocío."estudiante1.caminar(); // muestra "¡Estoy caminando!"

// Comprobamos que la herencia funciona correctamenteconsole.log(estudiante1 instanceof Persona); // devuelve trueconsole.log(estudiante1 instanceof Estudiante); // devuelve true

Si necesita más información al respecto, Douglas Crockford ofrece varios métodos alternativos para implementarla herencia en Javascript:

Herencia clásica: (http://javascript.crockford.com/inheritance.html)Herencia basada en prototipos: (http://javascript.crockford.com/prototypal.html)

Polimorfismo

Las diferentes clases hijas pueden definir métodos con el mismo nombre que la clase padre. Así, en el ejemploanterior de las clases Persona/Estudiante se puede, por ejemplo, modificar el método saludar de la clase hijapara que incluya información de la asignatura:

20

Page 21: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Definimos la clase padre 'Persona'function Persona(nombre) { // Propiedad de la clase padre this.nombre = nombre;}

// Método de la clase padrePersona.prototype.saludar = function() { console.log("Hola, Soy" + this.nombre);};

// Definimos la clase hija 'Estudiante'function Estudiante(nombre, asignatura) {

// Llamamos al constructor de la clase padre Persona.call(this, nombre);

// Propiedad de la clase hija this.asignatura = asignatura;};

// Hacemos que la clase Estudiante herede de la clase PersonaEstudiante.prototype = Object.create(Persona.prototype);Estudiante.prototype.constructor = Estudiante;

// PolimorfismoEstudiante.prototype.saludar = function () { console.log("Hola, soy " + this.nombre + ". Estudio " + this.asignatura + ".");};

var estudiante = new Estudiante('Manuel', 'Ingeniería de Software');estudiante.saludar();

Encapsulación

El encapsulamiento hace referencia a la agrupación de los elementos de una misma entidad (métodos ypropiedades). En el ejemplo anterior, las clases Persona y Estudiante agrupan sus propias funciones y atributos através de la función constructora y de sus prototipos, consiguiéndose el principio de encapsulamiento.

El término también puede hacer referencia a la restricción de acceso a estos métodos y propiedades fuera delobjeto. Una forma de ocultar el estado (propiedades) y métodos es utilizando funciones y variables anidadas. Sirvael siguiente código a modo de ejemplo:

21

Page 22: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

function Persona(nombre) { this.nombre = nombre // Propiedad pública var dni = null; // Propiedad privada

// Propiedad privada que permite a métodos privados acceder a variables públicas var that = this;

// Método público this.establecerDNI = function (nuevoDNI) { if( validarDNI() ) { dni = nuevoDNI; console.log('DNI de '+ that.nombre + ' validado y establecido'); } else { console.log('DNI inválido'); } };

// Método privado. Devuelve true si el DNI es válido function validarDNI(dni) { // ... return true; }}

var persona1 = new Persona("Rocío"); // Nuevo objeto persona1persona1.establecerDNI(1234567); // Muestra "DNI de Rocío válidado y establecido"persona1.dni; // muestra "undefined"

Abstracción

Mediante la abstracción se modela un elemento generalizándolo, esto es, eliminando particularidades y detallescomplejos del mismo. El modelo puede, posteriormente, acercarse a la realidad a través de una especializaciónde dicha abstracción.

Javascript permite la especialización por herencia y por composición.

. Artículo Wikipedia - Programación basada en prototipos(https://es.wikipedia.org/wiki/Programaci%C3%B3n_basada_en_prototipos) ↩

. Añadidos a la síntaxis de un lenguaje que facilitan expresar algunas construcciones de una forma másclara o concisa. Wikipedia (https://es.wikipedia.org/wiki/Az%C3%BAcar_sint%C3%A1ctico) ↩

. Introducción a Javascript orientado a objetos(https://developer.mozilla.org/es/docs/Web/JavaScript/Introducci%C3%B3n_a_JavaScript_orientado_a_objetos) ↩

1

2

3

22

Page 23: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Abstract Factory

Propósito

Porporciona una interfaz para crear familias de objetos relacionados o que dependen entre sí, sinespecificar sus clases concretas

Se encuentra íntimamente relacionado con el patrón "Factory Method", ya que encapsula a un grupo de factoriasconcretas con un objetivo común.

Mientras que el patrón "Factory Method" usa subclases pra crear instancias concretas de cada tipo de objetos,"Abstract Factory" define en una única clase la creación de objetos de diferente tipo (aunque pertenecientes a lamisma familia).

Implementación

El objeto "Creador" del código que se expone permite obtener diferentes "Productos" relacionados (cuadrado,círculo) usando una misma interfaz:

1

23

Page 24: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Producto abstractofunction Forma(opciones) { this.dibujar = function () { throw 'Método dibujar no implementado'; };}

// Producto Concreto: Circulofunction Circulo(opciones) { // Si no existe opciones.radio, usar el valor 0 this.radio = opciones.radio || 0;}

// Circulo es subclase de FormaCirculo.prototype = Object.create(Forma.prototype);Circulo.prototype.constructor = Circulo;

// Producto Concreto: Cuadradofunction Cuadrado(opciones) { this.lado = opciones.lado || 0;}

// Circulo es subclase de FormaCuadrado.prototype = Object.create(Forma.prototype);Cuadrado.prototype.constructor = Cuadrado;

// Creador abstractofunction FabricaGenerica() { this.crearForma = function (tipo, opciones) { throw 'Función no implementada'; };}

// Creador Concreto: FabricaDeFormasfunction FabricaDeFormas() { var formaPorDefecto = Circulo;

this.crearForma = function (tipo, opciones) { var formaAConstruir = formaPorDefecto; var opcionesRecibidas = opciones || 0; // Seleccinar subclase a construir switch (tipo) { case 'Circulo': formaAConstruir = Circulo; break; case 'Cuadrado': formaAConstruir = Cuadrado; break; }

return new formaAConstruir(opcionesRecibidas); };}

// Nueva fábricavar fabrica = new FabricaDeFormas();

// Solicitud de creación de objetosvar circulo1 = fabrica.crearForma('Circulo', { radio: 5 });var circulo2 = fabrica.crearForma(); // Devuelve un circulo de radio 0;var cuadrado = fabrica.crearForma('Cuadrado', { lado: 3 });

// Comprobación sobre objetos obtenidosconsole.log(circulo1 instanceof Circulo); // Devuelve Trueconsole.log(circulo2 instanceof Circulo); // Devuelve Trueconsole.log(cuadrado instanceof Cuadrado); // Devuelve True

24

Page 25: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

La clase "FabricaDeFormas" se ha implementado fijando los tipos de objetos a construir. Un diseño alternativo,más flexible, permite registrar los tipos de objeto a crear siempre que éstos dispongan del mismo patrón decreación:

// Creador Concreto: FabricaDeFormasfunction FabricaDeFormas() { var formas = {}; this.registrarForma = function (tipo, constructor) { formas[tipo] = constructor; }; this.crearForma = function (tipo, opciones) { var parametros = opciones || {}; var constructor = formas[tipo]; return (constructor ? new constructor(parametros) : null); };}

// Ejemplo de uso: Nueva fábricavar fabrica = new FabricaDeFormas();

// Registro de objetos a construirfabrica.registrarForma('Circulo', Circulo);fabrica.registrarForma('Cuadrado', Cuadrado);

// Construcción de objetosvar circulo = fabrica.crearForma('Circulo', { radio: 3 });var cuadrado = fabrica.crearForma('Cuadrado', { lado: 5 });

. el concepto de Factoría Concreta se describe en el apartado Factory Method ↩1

25

Page 26: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Builder

Propósito

Separa la construccion de un objeto complejo de su representación, de forma que el mismo proceso deconstrucción puede crear diferentes representaciones.

Gracias al patrón Constructor se divide la creación de un objeto complejo en pasos simples e independientes quedefinen cada parte del objeto.

Una clase, denominada Director, podrá crear diferentes objetos complejos (Productos) a través de cualquier claseque implemente los pasos necesarios (Constructor).

Se asume que el protocolo de construcción del objeto es conocido por el Constructor y el Director.

Gracias al patrón Builder ser solventan los problemas relacionados con el antipatron "telescoping constructor", elcual aparece cuando se usa un constructor con todos los parámetros del objeto como argumento. Al usar esteanti-patrón, cuando el objeto a crear va aumentando en complejidad (tiene más parámetros), se requiere modificael constructor existente o aumentar mediante polimorfismo el número de constructores. Como consecuencia, laaplicación debe adaptarse para usar estos nuevos constructores en todos los puntos donde se construya elobjeto. En cambio, al usar el patrón Builder se centraliza y simplifica la creación del objeto en cuestión,permitiendo diferentes construcciones a través de Builders personalizados.

Implementación

Supongamos que un ordenador/tablet queda representado por las siguientes características:

CPU.Memoria Ram.Capacidad de almacenamiento.

El siguiente ejemplo muestra una posible implementación de un objeto "Ordenador" y un objeto "Tablet"empleando el patrón Builder.

26

Page 27: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Builder Concreto: Ordenadorfunction EnsambladorOrdenador() { var producto = Object.create(null); producto.tipo = 'Ordenador';

this.cpu = function(cpu) { producto.cpu = cpu; }; this.ram = function(ram) { producto.ram = ram; }; this.capacidad= function(capacidad) { producto.capacidad = capacidad; }; this.extras = function() {}; // Extras no configurables

this.ensamblar = function() { return producto; };}

// Builder Concreto: Tabletfunction EnsambladorTablet() { var producto = Object.create(null); producto.tipo = 'Tablet';

this.cpu = function(cpu) { producto.cpu = cpu; }; this.ram = function(ram) { producto.ram = ram; }; this.capacidad = function(capacidad) { producto.capacidad = capacidad; }; this.extras = function() { producto.pantalla = '10pulgadas'; };

this.ensamblar = function() { producto.pantalla = '10inches'; return producto; };}

// Directorfunction Taller() { this.ensamblar = function(ensamblador) { ensamblador.cpu('i5'); ensamblador.ram('8Gb'); ensamblador.capacidad('1Tb'); ensamblador.extras();

return ensamblador.ensamblar(); } }

// Builders concretosvar ensambladorOrdenador = new EnsambladorOrdenador(); var ensambladorTablet = new EnsambladorTablet();

// Director que utilizará el builder concretovar taller = new Taller();

// Clientevar ordenador = taller.ensamblar(ensambladorOrdenador); // producto obtenido: ordenadorvar tablet = taller.ensamblar(ensambladorTablet); // producto obtenido: tablet

Gracias a este diseño el cliente obtiene diferentes productos (tablet, ordenador) empleando una misma interfazDirector (Taller). De la misma forma, a través de los Builders concretos la clase Director puede generar productosdiferentes siguiendo siempre la misma secuencia de acciones.

Si se requiere un producto diferente, basta con definir y emplear un nuevo Builder, siendo éste cambiotransparente en la interfaz Cliente-Director.

27

Page 28: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Factory Method

Propósito

Define una interfaz para crear un objeto, pero deja que sean las subclases quienes decidan qué claseinstanciar. Permite que una clase delegue en sus subclases la creación de objetos.

En vez de usar directamente el operador "New" o la herencia a través de prototipos usando "Object.create()",Factory Method desacopla la creación del nuevo objeto (llamado Producto) del componente que lo solicita,simplificando y encapsulando los detalles de instanciación en el objeto "Creador". A través de esta interfaz("Creador") se definen los métodos que las fábricas concretas emplearán para crear nuevos objetos.

A diferencia de Abstract factory, cada fábrica concreta sólo produce un tipo de objetos, por lo que la única forma decrer objetos diferentes es a través de una fábrica concreta distinta que implemente la misma interfaz.

Implementación

Haciendo uso del patrón Factory Method es posible obtener diferentes objetos (Cuadrado, Circulo) a través de unamisma interfaz "FabricaDeFormas":

28

Page 29: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Producto abstractofunction Forma ( opciones ) {}

// Producto Concreto: Circulofunction Circulo( opciones ) { // Si no existe opciones.radio, usar el valor 0 this.radio = opciones.radio || 0; }

// Producto Concreto: Cuadradofunction Cuadrado( opciones ) { this.lado = opciones.lado || 0;}

// Creador abstractofunction FabricaGenerica() { this.crearForma = function ( tipo, opciones ) { throw 'Función no implementada'; };}

// Creador Concreto: FabricaDeCirculosfunction FabricaDeCirculos() { this.crearForma = function ( opciones ) { var opcionesRecibidas = opciones || {}; return new Circulo( opcionesRecibidas ); };}

// Creador Concreto: FabricaDeCuadradosfunction FabricaDeCuadrados() { this.crearForma = function ( opciones ) { var opcionesRecibidas = opciones || {}; return new Cuadrado( opcionesRecibidas ); };}

// Creación de fábricas concretasvar fabricaDeCirculos = new FabricaDeCirculos();var fabricaDeCuadrados = new FabricaDeCuadrados();

// Uso de fábricasvar circulo1 = fabricaDeCirculos.crearForma( { radio: 5 } );var circulo2 = fabricaDeCirculos.crearForma(); // Devuelve un circulo de radio 0;var cuadrado = fabricaDeCuadrados.crearForma( { lado: 3 } );

// Comprobación de objetos creadosconsole.log(circulo1 instanceof Circulo); // Devuelve Trueconsole.log(circulo2 instanceof Circulo); // Devuelve Trueconsole.log(cuadrado instanceof Cuadrado); // Devuelve True

Si surge la necesidad de ampliar la fabrica para que contemple otros tipos de formas, basta con crear unasubclase de FabricaDeFormas sobreescribiendo el método "crearForma", o bien crear otra nueva fábrica queimplemente la interfaz FabricaGenerica.

Observe que javascript no posee el concepto de "interfaz", por lo que las interfaces "FabricaGenerica" y "Forma" sehan definido únicamente por convenio; nada impide a las clases concretas no implementar su interfazcorrectamente. No obstante, existen mecanismos en el lenguaje para emular el uso de interfaces en javascript

. Pro Javascript Design Patterns. Ros Harmes and Dustin Diaz. Apresss. 2008. Capítulo 2 ↩

1

1

29

Page 30: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Prototype

Propósito

Especifica los tipos de objetos a crear por medio de una instancia prototípica, y crea nuevos objetoscopiando este prototipo

En vez de crear nuevos objetos a partir de su definición mediante clases y herencia, el patrón clona en el nuevoobjeto las propiedades y métodos de otro ya existente. Gracias a Prototype se disminuye la herencia y el númerode clases, obteniendo un sistema más simple, flexible y, por tanto, reutilizable.

La implementación del patrón es inmediata al ser una característica propia del lenguaje javascript, el cual se basaen prototipos. Además, el código resultante está optimizado, pues las funciones definidas en el prototipo sonreferenciadas por los objetos clonados, con el consecuente ahorro de memoria que ello supone.

Implementación

Como se ha mencionado en el apartado anterior, la herencia a través de prototipos está definida en el estandardECMAScript 5. Para clonar un objeto se hace uso del método "Object.create" .

// Figura: Objeto prototipovar figura = { posicionX: 0, posicionY: 0,

mostrarPosicion: function() { console.log('Posición actual: ' + this.posicionX + ',' + this.posicionY);

},

mover: function( x, y ) { this.posicionX += x; this.posicionY += y; console.log('Nueva posición: ' + this.posicionX + ',' + this.posicionY); },};

// Rectangulo: Objeto clonado a partir de Figuravar rectangulo = Object.create(figura);

// Usar método clonado mover.rectangulo.mover(5,5); // Muestra 'Nueva posición: 5,5'

figura.mostrarPosicion(); // Muestra 'Posición actual: 0,0'rectangulo.mostrarPosicion(); // Muestra 'Posición actual: 5,5'

. Referencia de MDN:https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/create ↩

1

1

30

Page 31: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Singleton

Propósito

Garantiza que una clase sólo tenga una instancia, y proporciona un punto de acceso global a ella.

Existen situaciones en las que existe un único recurso debe ser compartido por el resto de participantes (porejemplo, un único puerto de comunicaciones RS232 compartido por varios elementos de la aplicación).

Una variable global, aunque proporciona un punto de acceso global, no garantiza el requisito de única instancia.Por otro lado, una clase/objeto estático, aunque cumple el cometido del patrón, obliga a que la inicialización delmismo se produzca en el mismo momento de su definición. En cambio, el patrón singleton permite postergardicha inicialización.

Existe una gran controversia respecto al uso de este patrón (llegando a ser considerado por algunos autorescomo un antipatrón ) debido a que introduce restricciones innecesarias en situaciones donde realmente no serequiere una sola clase, además de introducir un estado global en la aplicación y dificultar la capacidad del códigode ser probado.

Implementación

El código que se usa a modo de ejemplo usa la función Math.random() para obtener un número aleatorio, graciasal cual se identificará la instancia única creada por el objeto Singleton

var singleton = (function() {

var instancia; // Referencia a instancia única.

function iniciarInstancia() {

// Funciones y propiedades - Inicialmente privadas function raizCuadrada(numero) { return Math.sqrt(numero); } var numeroAleatorio = Math.random();

// Funciones y propiedades publicas return { raiz: raizCuadrada, identificador: numeroAleatorio }; }

return { obtenerInstancia: function() { if ( !instancia ) { instancia = iniciarInstancia(); } return instancia; } };

})();

var objeto1 = singleton.obtenerInstancia();var objeto2 = singleton.obtenerInstancia();

// objeto1 y objeto2 referencian a la misma instancia,// por lo que ambos deben tener el mismo identificadorconsole.log(objeto1.identificador === objeto2.identificador); // true

12

31

Page 32: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Según el libro "Design Patterns", la instancia debe ser extensible a través de la herencia, y los clientes deberíanpoder extender instancias sin modificar su código. Para cumplir con este requisito basta con sobreescribir lafunción "obtenerInstancia" para que cree una instancia diferente en vez de llamar al método privado"iniciarInstancia()"

. Artículo en google Code sobre la controversia sobre el patrón Singleton(https://code.google.com/archive/p/google-singleton-detector/wikis/WhySingletonsAreControversial.wiki) ↩

. Scott Densmore. Why singletons are evil(https://blogs.msdn.microsoft.com/scottdensmore/2004/05/25/why-singletons-are-evil/( ↩

1

2

32

Page 33: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Adapter

Propósito

Convierte la interfaz de una clase en otra distinta que es la que esperan los clientes. Permite que cooperenclases que de otra manera no podrían por tener interfaces incompatibles.

Facilita la reutilización de código, adaptando la interfaz de una clase existente en otra compatible con el cliente quedesea usar objetos de dicha clase. El patrón emplea la siguiente terminología:

Objetivo: Interfaz que espera el cliente.Cliente: usuario que empleará la interfaz objetivo para comunicarse con la clase a adaptar.Adaptable: clase existente cuya interfaz necesita ser adaptadaAdaptador: clase "envoltorio" que adapta la interfaz del adaptable a la interfaz objetivo.

Adapter presenta similitudes con Facade, ya que ambas envuelve un objeto para modificar la interfaz que éstepresenta al exterior. No obstante, mientras que Facade presenta una interfaz simplificada (sin opcionesadicionales, haciendo suposiciones con objeto de simplificar la interfaz), Adapter no pretende disminuir lacomplejidad ni funcionalidad de la interfaz; en su lugar, su objetivo se limita a adaptar dicha interfaz para hacerlacompatible con el cliente que desea usar la clase. Se trata pues de una adaptación sintáctica, y no semántica.

Implementación

La aplicación que se expone requiere la consulta del precio de un producto a diferentes servicios en línea. Cadaservicio expone una interfaz diferente al exterior, pero se desea que la aplicación use una API unificada paracomunicarse con cada uno de ellos, por lo que el uso del patrón Adapter está justificado

// Objetivo: Interfaz// function obtenerPrecio ( producto )

// Clientefunction Cliente(){ var servicios = {}; this.agregarServicio = function ( nombre, adaptador ) { servicios[nombre] = adaptador; };

// Lista precios ofrecidos por los diferentes servicios // usando la interfaz objetivo this.listarPrecios = function ( producto ) { for(var servicio in servicios) { var precio = servicios[servicio].obtenerPrecio( producto ); console.log( servicio + ': ' + precio ); } };}

// Adaptable: API del Servicio 1function Amazon() {

this.getPriceOf = function(price, taxes) { var prize; // ... prize = 5; // ... return ( prize*(1+taxes) ); };

// ...}

33

Page 34: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Adaptador del Servicio 1function AdaptadorAmazon() { this.obtenerPrecio = function ( producto ) { return amazon.getPriceOf( producto, 0.21 ); };}

// Adaptable: API del Servicio 2function ElCorteIngles() {

this.pvp = function (producto) { var precio; // ... precio = 7; // ... return precio; }}

// Adaptador del Servicio 2function AdaptadorElCorteIngles() { this.obtenerPrecio = function ( producto ) { return elCorteIngles.pvp(producto); };}

// Ejemplo de uso

// Instancias de cliente y serviciosvar cliente = new Cliente();var amazon = new Amazon();var elCorteIngles = new ElCorteIngles();

// Instancias de adaptadoresvar adaptadorAmazon = new AdaptadorAmazon();var adaptadorElCorteIngles = new AdaptadorElCorteIngles();

// Registro de servicios en cliente;cliente.agregarServicio('Amazon', adaptadorAmazon);cliente.agregarServicio('El Corte Ingles', adaptadorElCorteIngles);

// Listado de precios de productocliente.listarPrecios('Playstation 4');

34

Page 35: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Bridge

Propósito

Desacopla una abstracción de su implementación, de manera que ambas puedan variar de formaindependiente

En programación orientada a objetos, cuando una abstracción puede tener varias implementaciones se suelecrear una clase abstracta que define la interfaz, siendo las subclases quienes lleven a cabo las diferentesimplementaciones. Esta solución dificulta modificar, extender y reutilizar la abstracción e implementaciones deforma independiente, pues ambas clases se encuentran fuertemente acopladas.

Para resolverlo, el patrón Bridge desacopla la interfaz y la implementación haciendo que ambas pertenezcan ajerarquías de clases diferentes. Para ello, define los siguientes participantes:

Abstracción: Interfaz de la abstracción. Contiene una referencia a un objeto "Implementador".AbstracciónRefinida: Subclase de "Abstracción" (extiende la interfaz original).Implementador: Interfaz de las clases de implementación. Suele proporcionar operaciones primitivas queserán usadas por "Abstracción" en operaciones de más alto nivel.ImplementadorConcreto: Clase que usa la interfaz "Implementador"

De la enumeración anterior se deduce que Bridge requiere dos interfaces para desacoplar la abstracción de laimplementación, por lo que se suele considerar al patrón como una única abstracción formada por dos capas.

La relación entre ambas jerarquías ("Abstracción" e "Implementador") a través de la referencia de la primera haciala segunda es lo que se conoce como "puente", pues hace de nexo entre ambas interfaces.

Por último, merece la pena destacar las diferencias frente al patrón Adapter: mientras que el primero tiene comoobjeto adaptar dos interfaces existentes que son incompatibles entre sí, el segundo pretende desacoplar interfazde implementación, promoviendo "composición sobre herencia" en el diseño.

Implementación

Suponga que necesita diseñar un sistema de ventanas compatible con los sistemas operativos más popularesdel mercado. La primera capacidad que se desea implementar es la de crear nuevas ventanas con fondo opaco otransparente. Una posible solución de diseño se muestra en las siguientes líneas:

// Con patrón BRIDGE://// Escritorio <--- Pintar// / \ / \// Windows Unix conTransparencia conRelleno

//// Implementación//

// Implementadorfunction Pintar () {

this.pintarVentana = function () { throw "pintarVentana no implementado"; };}

// ImplementadorConcreto 1function PintarConRelleno () {

35

Page 36: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

this.pintarVentana = function () { // ... Implementación console.log('Ventana pintada con fondo opaco'); };}

// ImplementadorConcreto 2function PintarConTransparencia () {

this.pintarVentana = function () { // ... Implementación console.log('Ventana pintada con fondo transparente'); };

}

// Abstracciónfunction Escritorio( implementador ) {

// Referencia a objeto con interfaz "Implementador" var pintar = implementador;

// Interfaz de Abstracción this.nuevaVentana = function () { throw "nuevaVentana no implementado"; };}

// Abstracción Refinada 1function EscritorioWindows ( implementador ) {

// Referencia a objeto con interfaz "Implementador" var pintar = implementador;

// Interfaz de Abstracción this.nuevaVentana = function () { console.log('Nueva ventana en S.O Windows.'); pintar.pintarVentana(); };

// Resto de métodos específicos de Escritorio Windows // ...}

// Abstracción Refinada 2function EscritorioUNIX ( implementador ) {

// Referencia a objeto con interfaz "Implementador" var pintar = implementador;

// Interfaz de Abstracción this.nuevaVentana = function () { console.log('Nueva ventana en S.O UNIX.'); pintar.pintarVentana(); };

// Resto de métodos específicos de Escritorio UNIX // ...}

// Ejemplo de Uso

// Cliente: Crea Implementadores concretos.var pintarUsandoTransparencia = new PintarConTransparencia();var pintarUsandoRelleno = new PintarConRelleno();

// Cliente: crea Abstracciones refinadas usando los Implementadores concretosvar escritorioWindows = new EscritorioWindows ( pintarUsandoRelleno );

36

Page 37: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

var escritorioUNIX = new EscritorioUNIX ( pintarUsandoTransparencia );

// Cliente: usa la interfaz ofrecida por Abstracción,// la cual a su vez empleará la interfaz ofrecida por ImplementadorescritorioWindows.nuevaVentana(); // Crea una nueva ventana con fondo opacoescritorioUNIX.nuevaVentana(); // Crea una nueva ventana con fondo transparente

// Sin patrón BRIDGE (usando herencia)://// Escritorio(Interfaz: PintarVentana)// / \// Windows Unix// / \ / \// conTransparencia conRelleno conTransparencia conRelleno

// // Implementación//

// ...

El patrón Bridge se encuentra muy extendido en la programación orientada a eventos y en el diseño de APIs ,pues promueve la creación de componentes modulables y verificable.

. Puede encontrar ejemplos de ello en el capítulo 8 del libro "Pro Javascript Design Patterns", de RossHarmes y Dustin Diaz. Editorial Apress.2008 ↩

1

1

37

Page 38: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Composite

Propósito

Combina objetos en estructuras de árbol para representar jerarquías de parte-todo. Permite que los clientestraten de manera uniforme a los objetos individuales y compuestos.

Permite tratar a una colección de objetos de la misma forma en la que se trata a cada objeto particular. Para ello,la colección implementa las mismas operaciones que implementan cada objeto de forma individual, de forma queuna operación ejecutada sobre el conjunto se ejecuta en cada uno de sus miembros.

Además, este patrón de diseño organiza los elementos en una estructura en árbol, permite que éste sea recorridoy habilita métodos para recuperar cualquier nodo/hoja del mismo.

En la definición de Composite de GoF se distinguen cuatro colaboradores:

Componente: Interfaz de los objetos individuales y métodos para acceder a los hijos y al padre.Compuesto: Objeto que almacena componentes hijos. Implementa las operaciones de la interfaz"Componente" relacionadas con los hijos.Hoja: Representa a un objeto sin hijos dentro de la colección.Cliente: Manipula a los objetos de la composición usando la interfaz componente.

Cabe destacar que cada composición dentro de la colección tiene una relación de pertenencia (el componente ATIENE el hijo B), y no una relación de generalización/especialización (clase/subclase).

Implementación

Con el fin de mostrar la implementación de Composite, se ha definido la estructura en árbol de un menúalimenticio compuesto por un plato de arroz con tomate y un flan para el postre. Cada objeto compuesto (es decir,cada plato) está a su vez formado por ingredientes simples. Gracias al patrón de diseño, el cálculo de calorías delmenú o la búsqueda de alérgenos se vuelve trivial.

// Componente: Objeto básico individualfunction IngredienteBasico(nombre, calorias, contieneGluten, contieneLactosa) {

var id = nombre; var aporteCalorico = calorias; var conGluten = contieneGluten; var conLactosa = contieneLactosa;

// Interfaz de objeto básico this.obtenerNombre = function () { return id; }; this.obtenerCalorias = function () { return aporteCalorico; }; this.contieneGluten = function () { return conGluten; }; this.contieneLactosa = function () { return conLactosa; };}

// Compuesto: Implementa la interfaz de componente,// aplicada a todos los hijosfunction IngredienteCompuesto(nombre) { var id = nombre;

// Referencia a hijos var ingredientes = [];

// Métodos para gestionar hijos this.agregarIngrediente = function (ingrediente) { ingredientes.push( ingrediente );

12

38

Page 39: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

}

// Interfaz de objeto básico, considerando a los hijos this.obtenerNombre = function () { return id; };

this.obtenerCalorias = function () { var totalCalorias = 0; ingredientes.forEach(function ( ingrediente ) { totalCalorias += ingrediente.obtenerCalorias() });

return totalCalorias; };

this.contieneGluten = function () { var conGluten = false; ingredientes.forEach(function ( ingrediente ) { conGluten = conGluten || ingrediente.contieneGluten() ; });

return conGluten; };

this.contieneLactosa = function () { var conLactosa = false; ingredientes.forEach(function ( ingrediente ) { conLactosa = conLactosa || ingrediente.contieneLactosa() ; }); return conLactosa; };}

// Ejemplo de uso

// Ingredientes básicosvar huevo = new IngredienteBasico('huevo', 155, false, false);var leche = new IngredienteBasico('leche', 141, false, true);var pan = new IngredienteBasico('leche', 141, true, false);var azucar = new IngredienteBasico('azucar', 265, false, false);var arroz = new IngredienteBasico('arroz', 130, false, false);var tomate = new IngredienteBasico('tomate', 18, false, false);

// Plato simplevar arroz_con_tomate = new IngredienteCompuesto('arroz_con_tomate');arroz_con_tomate.agregarIngrediente( arroz );arroz_con_tomate.agregarIngrediente( tomate );

// Postre simplevar flan = new IngredienteCompuesto('flan');flan.agregarIngrediente( leche );flan.agregarIngrediente( huevo );flan.agregarIngrediente( azucar );

console.log(arroz_con_tomate.obtenerCalorias()); // Muestra '148'console.log(flan.contieneLactosa()); // Devuelve true;console.log(arroz_con_tomate.contieneGluten()); // Devuelve 'false'

// Agregamos pan al arroz con tomatearroz_con_tomate.agregarIngrediente( pan );console.log(arroz_con_tomate.contieneGluten()); // Devuelve 'true'

. Relación HAS-A (https://en.wikipedia.org/wiki/Has-a) ↩

. Relación IS-A (https://en.wikipedia.org/wiki/Is-a) ↩

1

2

39

Page 40: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Decorator

Propósito

Añade dinámicamente nuevas responsabilidades a un objeto, proporcionando una alternativa flexible a laherencia para extender la funcionalidad.

El patrón es útil cuando necesitamos añadirle responsabilidades a objetos individuales, y no a todos los objetosde una clase. La herencia queda, por tanto, descartada.

Es especialmente útil cuando un objeto puede contener un gran número de características diferentes, por lo quedefinir una subclase para cada una de las posibles combinaciones generaría demasiado código difícil demanejar, mantener y reusar. En su lugar, Decorator define un objeto base y agrega propiedades al mismo (lodecora).

En lenguajes estáticos la implementación del patrón se realiza envolviendo al objeto con otro nuevo que posee lamisma interfaz y añade funcionalidades; se crea un objeto "Decorador" que contiene una referencia del objeto"Decorado", y se redirigen las peticiones hacia éste a través del "Decorador" .

Por la naturaleza de javascript, agregar atributos/métodos a objetos es un proceso sencillo, por lo que laimplementación del patrón se simplifica considerablemente .

Implementación

A continuación se muestra, haciendo uso del patrón Decorator, cómo agregar piezas a un componente base("ordenador") través de diferentes "Decoradores".

1

2

40

Page 41: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Componente basefunction Ordenador() { this.cpu = 'i5'; // Nombre comercial this.ram = 4; // Gigabytes this.hdd = 1; // Terabytes

this.precio = function () { var precioBase = 500; return precioBase; };}

// Decorador concreto 1: Agrega tarjeta gráfica dedicadafunction graficaDedicada( ordenador ) { ordenador.graficaDedicada = 'GeForce GTX 1060';

// Decora la función precio agregando el coste de la tarjeta. var precioActual = ordenador.precio(); ordenador.precio = function () { var precioConGrafica = precioActual + 300; return precioConGrafica; };}

// Decorador concreto 2: Agrega impuestosfunction impuestosPeninsula ( ordenador ) { ordenador.impuestos = 0.21;

// Decora la función precio agregando impuestos var precioActual = ordenador.precio(); ordenador.precio = function () { var precioConImpuestos = precioActual * (1 + ordenador.impuestos); return precioConImpuestos; };}

// Ejemplo de uso: nuevo componente basevar ordenador = new Ordenador();

// Decorar agregándole una tarjeta gráfica dedicadagraficaDedicada(ordenador);

// Decorar agregándole los impuestos de la zona.impuestosPeninsula (ordenador);

// Comprobación del resultado// Precio total: (500 +300)*1.21console.log(ordenador.precio()); // Muestra '968' console.log(ordenador.graficaDedicada); // Muestra 'GeForce GTX 1060'

. Un ejemplo de implementación del diseño clásico se encuentra en el libro "Pro JavaScript DesignPatterns". Ross Harmes and Dustin Diaz. Apress 2008. Capítulo 12. ↩

. Puede encontrar implementaciones alternativas en el libro "Javascript Patterns". Stoyan Stefanov. O-Reilly.2010. Capítulo 7. ↩

1

2

41

Page 42: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Facade

Propósito

Proporciona una interfaz unificada para un conjunto de interfaces de un subsistema. Define una interfaz dealto nivel que hace que el subsistema sea más fácil de usar.

Gracias a Facade la apariencia de un sistema complejo puede simplificarse, exponiendo al exterior una API dealto nivel que abstrae la maraña interna de componentes. Como contrapartida, esta simplifición de la realidadpuede llevar consigo la disminución de servicios ofrecidos o una falta de eficiencia del código resultante.

Implementación

Suponga que una aplicación dispone de una base de datos en la que existe una tabla llamada "Personas" quecontiene los campos 'nombre' y 'edad'. Además, la aplicación permite hacer consultas SQL estándar, de forma quepara obtener una relación de todas las personas mayores de edad habría que ejecutar la sentencia "SELECT * FROMPESONAS WHERE EDAD >= 18"

Para simplificar la interacción con la base de datos, el siguiente código define, haciendo uso del patrón fachada,la función "seleccionar":

// Función compleja Databasefunction BaseDeDatos() { this.connect = function ( usuario, password ) { // ... Implementación ... };

this.sql = function ( sentencia ) { console.log( 'Consulta realizada: ' + sentencia ); // ... Implementación ... };

// ... Resto de funciones ...}

// Instancia de base de datosvar baseDeDatos = new BaseDeDatos();

// Función tipo Facadefunction seleccionar( tabla, filtro ) { return baseDeDatos.sql("SELECT * FROM " + tabla + " WHERE " + filtro);}

// Ejemplo de uso:// Muestra 'Consulta realizada: SELECT * FROM PERSONAS WHERE >= 18`// Recibe un listado de todas las personas mayores de edadvar personasMayoresDeEdad = seleccionar( 'PERSONAS', '>= 18');

El ejemplo anterior, aunque muy simplificado e inválido en un entorno de producción (no se han tenido en cuentaconsideraciones de seguridad y se presupone que el usuario empleará nombres de tablas y filtros válidos),expone una interfaz mucho más clara y sencilla para quienes desconozcan el lenguaje SQL.

Muchas librerías populares javascript hacen uso del patrón Facade para simplificar la interacción del usuario conel navegador. Un ejemplo de ello es JQuery y sus "Selectores" .

. Página web de JQuery (https://api.jquery.com/category/selectors/) ↩

1

1

42

Page 43: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Flyweight

Propósito

Usa el compartimento para permitir un gran número de objetos de grano fino de forma eficiente.

En aplicaciones que contienen un gran número de objetos se requiere una gran capacidad de memoria. Cuandodichos objetos contienen cierta cantidad de código repetitivo, la aplicación está haciendo un uso ineficiente de losrecursos, pues cada objeto contiene una porción de código repetida cuando realmente podría ser compartida portodos los objetos.

El patrón describe cómo compartir pequeños objetos (llamados "Peso ligero") para permitir su uso en el resto decomponentes, optimizando así el uso de memoria de la aplicación. Tiene gran relevancio, por tanto, enaplicaciones que hacen uso intensivo de la memoria y requieren manejar una gran cantidad de información.

Para separar la información "común", la cual se compartirá, del resto de información, el patrón define el conceptode estado intrínseco/extrínseco de un objeto. Así, el estado intrínseco hace referencia a las propiedades del objetoque serán compartidas, mientras que el extrínseco es la colección de propiedades que quedan fuera del objetocompartido. Por ejemplo, un objeto con las propiedades "marca, modelo, propietario, fecha de compra" puededividirse en un objeto compartida con estado intrínseco "marca, modelo"y estado extrínseco "propietario, fecha decompra", de forma que sólo existirá un objeto compartido por cada tupla "marca, modelo" donde antes existíanmuchos más objetos con información repetida.

La información asociada al estado intrínseco se almacena en el objeto compartido, mientras que el estadoextrínseco se almacenará en otro lugar externo a dicho objeto (por ejemplo, en los objetos que emplean lainformación compartida).

Cabe destacar que la separación de las propiedades/métodos de un objeto en estado intrínseco y extrínseco essubjetiva y depende de la aplicación.

Para la creación de los objetos compartidos se suele emplear el patrón Factory Method, haciendo que la fábricadevuelva referencias de los objetos compartidos si estos ya han sido solicitados con anterioridad, o bien creandonuevos objetos compartidos si aún no existe una instancia de los mismos. Efectivamente, el patrón Singletontambién aparece en el escenario para crear instancias únicas y compartidas.

Implementación

A modo de ejemplo, el siguiente código optimiza en cuanto a uso de memoria la gestión de todos los vehículosregistrados en un país, caracterizados por los parámetros (marca, modelo, Año de fabricación, número debastidor, NIF del propietario, dirección del propietario, teléfono de contacto del propietario)

// Objeto optimizado como peso ligero: cochefunction Coche ( marca, modelo, anio) {

// Estado intrínseco this.marca = marca; this.modelo = modelo; this.anioDeFabricacion = anio;}

// Fábrica de objetos ligerosfunction FabricaDeCoches() {

var listadoDeCoches = {}; // marca-modelo-anio: instancia

this.crearCoche = function ( marca, modelo, anio ) {

43

Page 44: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Implementación singleton var referencia = marca + '-' + modelo + '-' + anio; if( listadoDeCoches[referencia] ) { return listadoDeCoches[referencia]; } else { var coche = new Coche(marca, modelo, anio); listadoDeCoches[referencia] = coche; return coche; } };}

// Gestión del estado extrínseco function BaseDeDatosDeVehiculos () {

var listadoDeVehiculos = {}; // bastidor: {nif, direccion, telefono, coche}

// Agregar nuevo registro this.nuevoRegistro= function (marca, modelo, anio, bastidor, nif, direccion, telefono) { var coche = fabricaDeCoches.crearCoche(marca, modelo, anio); listadoDeVehiculos[bastidor] = { // Estado extrínseco nif: nif, direccion: direccion, telefono: telefono,

// Referencia a objeto peso ligero coche: coche }; };

// Consultar registro en base a identifidor único (bastidor) this.obtenerRegistro = function ( bastidor ) { return listadoDeVehiculos[ bastidor ]; };}

// Ejemplo de uso:// Creación de la fábrica de objetos ligerosvar fabricaDeCoches = new FabricaDeCoches();

// Creación de la base de datos de vehículosvar baseDeDatos = new BaseDeDatosDeVehiculos();

// Registro de los dos primeros vehículos del paísbaseDeDatos.nuevoRegistro('clement', 'triciclo', 1900, 1, '1234A', 'Palma de Mallorca', 'C/ Automoción', 'N/A');baseDeDatos.nuevoRegistro('clement', 'triciclo', 1900, 2, '5678B', 'Cáceres', 'C/ Marqués', 'N/A');

// Obtenemos registrosvar registro1 = baseDeDatos.obtenerRegistro(1);var registro2 = baseDeDatos.obtenerRegistro(2);

// Comprobamos que ambos registros referencian al mismo objeto "coche"console.log( registro1.coche === registro2.coche); // Muestra 'True'

Además del objeto coche, podríamos haber optimizado la información relativa al usuario convirtiéndola en otroobjeto "Peso ligero", minimizando aún más el uso de memoria.

El sistema resultante es, no obstante, más complejo que su versión sin optimizar, pues la información se hallarepartida en dos objetos diferentes donde antes sólo existía uno. Además, ha sido necesaria la implementaciónde una fábrica y dos clases Singleton (baseDeDatos también mantiene un listado de registros único).

44

Page 45: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Proxy

Propósito

Proporciona un sustituto o representante de otro objeto para controlar el acceso a éste.

Un proxy es un objeto que puede ser usado para controlar el acceso a otro objeto denominado "Sujeto". El proxypuede ser instanciado en lugar del objeto real al que controla. Puede, además, retrasar la instanciación del objetoreal hasta el momento en que éste sea realmente utilizado . Éste último hecho tiene especial interés encomponentes cuya inicialización requiere un alto consumo de recursos, pues permite una carga inicial rápida:

Si el objeto real no se llega a utilizar, entonces nunca será instanciado.Si se sabe que el objeto real será requerido, entonces permite una carga en segundo plano mientrascontinúa el resto de la aplicación.

Mientras que el patrón Facade encapsula la llamada de varios métodos complejos a través de un método simple,Proxy se sitúa entre el cliente de un objeto y el objeto mismo, protegiendo su acceso para favorecer los siguientesaspectos:

El acceso local a un recurso remoto (proxy remoto).La inicialización de objetos costosos (proxy virtual).La seguridad en el acceso a un recurso protegido (proxy de protección).Conteo de referencias al objeto real.Facilitar la comcurrencia cuando el objeto real es un objeto compartido.

Implementación

El código de ejemplo emplea el patrón Proxy con múltiples propósitos

Retrasar la instanciación de la clase Geolocalizador hasta el momento en que ésta es necesaria.Guardar en memoria local los resultados durante las diferentes peticiones al servicio de geolocalización,disminuyendo el número de accesos remotos

// Sujetofunction Geolocalizador() {

// Proceso de inicialización costoso en tiempo. this.iniciar = function (){ // implementación };

// Obtiene coordenadas de un servicio de mapas this.coordenadasDe = function ( ciudad ) { // Implementación // Petición remota a servidor de mapas // ...

// Ejemplo de respuestas var ciudadEnMayusculas = ciudad.toUpperCase(); switch (ciudadEnMayusculas) { // En orden alfabético case 'BARCELONA': return '41.385064, 2.173403'; break; case 'MADRID': return '40.416775, -3.703790'; break; case 'SEVILLA': return '37.389092, -5.984459'; break;

1

45

Page 46: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

case 'VALENCIA': return '39.469907, -0.376288'; break; } };}

// Proxyfunction GeoProxy() { var geolocalizador; // Referencia a Sujeto

// Caché local de consultas a geolocalizador var cache = {};

// Dato estadístico. Consultas realizadas a geolocalizador var consultasAGeolocalizador = 0;

this.coordenadasDe = function ( ciudad ) {

// Variable auxiliar var ciuidadEnMayusculas = ciudad.toUpperCase();

// Devolver el resultado almacenado en caché, si existe. if( cache[ciuidadEnMayusculas] ) { return cache[ciuidadEnMayusculas]; }

// Lazy loading: instanciación del geolocalizador si // aún no se ha solicitado ninguna ciudad. if( !geolocalizador ) { geolocalizador = new Geolocalizador(); geolocalizador.iniciar(); }

// Solicitud de coordenadas cache[ciuidadEnMayusculas] = geolocalizador.coordenadasDe( ciudad ); consultasAGeolocalizador++;

return cache[ciuidadEnMayusculas]; };

// Estadísticas de solicitudes diarias. this.consultasRemotas = function () { return consultasAGeolocalizador; };}

// Ejemplo de uso

// Instanciación de geoProxy (retrasa creación de geolocalizador)var geoProxy = new GeoProxy();

// Solicitud de primera ciudad:// - Proxy creará instancia de geolocalizador// - Proxy realizará la primera solicitud a geolocalizadorconsole.log( geoProxy.coordenadasDe( 'Sevilla' ) );

// Solicitud de segunda ciudad:// - Proxy usará la instancia existente de geolocalizador// - Proxy realizará la segunda solicitud a geolocalizadorconsole.log( geoProxy.coordenadasDe( 'Madrid' ) );

// Solicitud de tercera ciudad:// - Proxy usará la caché interna para devolver resultadoconsole.log( geoProxy.coordenadasDe( 'Sevilla' ) );

// Número de accesos a servicio remotoconsole.log( geoProxy.consultasRemotas() ); // Devuelve '2'

46

Page 47: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Gracias al patrón se disminuyen los tiempos de acceso a la aplicación y se mejoran los tiempos de acceso aconsultas repetidas en la sesión. Como cnotrapartida, al igual que sucede con el resto de patrones, Proxy añadecomplejidad a la solución.

. Este concepto se conoce como carga diferida (lazy loading) (https://es.wikipedia.org/wiki/Lazy_loading) ↩1

47

Page 48: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Chain of Responsibility

Propósito

Evita acoplar el emisor de una petición a su receptor, al dar a más de un objeto la posibilidad de respondera la petición. Crea una cadena con los objetos receptores y pasa la petición a través de la cadena hasta queésta sea tratada por algún objeto.

El patrón permite a un objeto transmisor enviar una petición a un una cadena de uno o varios objetos receptores.Cada elemento de la cadena receptora procesa la petición y/o la traslada al objeto contiguo. Por tanto, cadaeslabón de la cadena sólo conoce a sus elementos adyacentes.

El transmisor sólo se comunica con el primer objeto de la cadena. La petición se envía a través de un objetodedicado que contiene toda la información, o bien llamándo a un método del objeto receptor sin argumentos (encuyo caso la invocación del método es la petición en sí misma). Cualquier nodo de la cadena receptora puederealizar 3 acciones diferentes:

Procesar completamente la petición y dar por finalizada la operación, en cuyo caso no traslada la petición alsiguiente receptor.Procesar parcialmente la solicitud, modificarla (si es necesario) y trasladarla al siguiente elemento.No procesar la petición y trasladarla íntegramente al nodo contiguo.

En la definición del patrón se denomina "Cliente" al transmisor de la petición, "Manejador" a la interfaz usada porlos receptores para tratar las peticiones y enlazarse con el siguiente nodo de la cadena, y "ManejadorConcreto" acada uno de los eslabones de la cadena que implementan la interfa "Manejador".

Es recomendable usar este diseño cuando existe más de un objeto que puede manejar una misma petición, peroel cliente no conoce a priori (o no desea especificar ) cual de ellos debería procesarla. También se aconseja enescenarios en los que se requiere especificar dinámicamente a los receptores.

En aplicaciones web, Chain of Responsibility se emplea en el manejo de eventos. Cuando un elemento del DOMdispara un evento (por ejemplo, notificando una pulsación de ratón sobre él), el navegador lo captura y propagade forma jerárquica, comenzando por el elemento que inició el evento, ascendiendo hasta su nodo padre yllegando hasta el nodo raíz en caso de que ningún componente de la cadena maneje la petición.

Implementación

El funcionamiento de una máquina de cambio de billetes encaja perfectamente con la filosofía del patrón:

12

48

Page 49: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Manejadorfunction Expendedor ( unidades ) {

var valorDelBillete = unidades; var sucesor;

this.siguiente = function ( expendedor ) { sucesor = expendedor; };

this.cambiar = function ( cantidad ) { var numeroDeBilletes = Math.floor(cantidad / valorDelBillete); var noDispensable = cantidad - (numeroDeBilletes * valorDelBillete);

if( numeroDeBilletes > 0) { console.log(numeroDeBilletes + ' billetes de ' + valorDelBillete + ' dispensados'); }

if ( noDispensable > 0 && sucesor ) { sucesor.cambiar ( noDispensable); } else if ( noDispensable ) { console.log('No se ha podido dar cambio de ' + noDispensable); } };}

// Manejadores Concretovar expendedorDeCincoUnidades = new Expendedor(5);var expendedorDeDiezUnidades = new Expendedor(10);var expendedorDeVeinteUnidades = new Expendedor(20);var expendedorDeCincuentaUnidades = new Expendedor(50);

// Establecer cadena:expendedorDeCincuentaUnidades.siguiente( expendedorDeVeinteUnidades );expendedorDeVeinteUnidades.siguiente( expendedorDeDiezUnidades );expendedorDeDiezUnidades.siguiente( expendedorDeCincoUnidades );

// Clientefunction MaquinaDeCambio( expendedor ) { var expendedorInicial = expendedor;

this.darCambioDe = function ( cantidad ) { expendedorInicial.cambiar( cantidad ); };

}

// Ejemplo de uso

var maquinaDeCambio = new MaquinaDeCambio(expendedorDeCincuentaUnidades);maquinaDeCambio.darCambioDe(123);

Un inconveniente de encadenar a los receptores es que el transmisor no conoce a priori quién ha respondido a lapetición, ni si ésta ha sido resuelta satisfactoriamente. Para resolverlo, el último elemento de la cadena puedeprovocar una excepción en caso de que no pueda satisfacer el resto de la petición.

. Document Object Model (https://es.wikipedia.org/wiki/Document_Object_Model) ↩

. Para entender el por qué del funcionamiento actual de los navegadores web, se recomienda el visionadode "Douglas Crockford: An Inconvenient API - The Theory of the DOM" (https://www.youtube.com/watch?v=Y2Y0U-2qJMs) ↩

1

2

49

Page 50: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Command

Propósito

Encapsula una petición en un objeto, permitiendo así parametrizar a los clientes con distintas peticiones,encolar o llevar un registro de las peticiones y poder deshacer las operaciones.

Tal y como menciona el libro "Design Patterns" (GoF), existen situaciones en las que es necesario solicitaroperaciones a objetos sin que se conozcan detalles de la acción o al receptor real de la misma.

El patrón Command permite encapsular la operación en un único objeto, el cual puede ser pasado al componenteencargado de realizar dicha operación a través de una interfaz conocida. Como consecuencia, el objeto quesolicita la operación y el objeto que la ejecuta quedan completamente desacoplados.

Los elementos que intervienen en el patrón son:

Comando: Declara una interfaz para ejecutar una operación. Por ejemplo, declara el método "Ejecutar".ComandoConcreto: Implementa el método Ejecutar, el cual invoca las operaciones necesarias en el Receptorpara llevar a cabo la orden.Cliente: Crea un objeto ComandoConcreto y establece su Receptor.Invocador: Le pide al objeto ComandoConcreto que ejecute la peticiónReceptor: es el objeto en donde se ejecutará realmente el comando.

Implementación

El siguiente ejemplo muestra el uso del patrón en una calculadora básica que permite las operaciones de suma yresta.

// Receptor. Implementa las acciones reales a ejecutarfunction Calculadora() { var valorActual = 0;

this.incrementar = function ( numero ) { valorActual += numero; console.log("Nuevo valor: " + valorActual); };

this.disminuir = function ( numero ) { valorActual -= numero; console.log("Nuevo valor: " + valorActual); };}

// Interfaz Comando: define funciones ejecutar, deshacerfunction Comando () { this.ejecutar = function(valor) { throw "Interfaz no implementada"; };

this.deshacer = function() { throw "Interfaz no implementada"; };}

// Comando Concreto: implementa funciones ejecutar, deshacerfunction ComandoAgregar ( receptor, numero) { var claseReceptora = receptor; var valor = numero;

this.ejecutar = function() {

50

Page 51: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

claseReceptora.incrementar( valor ); };

this.deshacer = function() { claseReceptora.disminuir( valor ); };}

// Comando Concreto: implementa funciones ejecutar, deshacerfunction ComandoSustraer ( receptor, numero ) { var claseReceptora = receptor; var valor = numero;

this.ejecutar = function( ) { claseReceptora.disminuir( valor); };

this.deshacer = function() { receptor.incrementar(valor); };}

// Cliente: crea los comandos y asigna receptorfunction Cliente( receptor ) { this.comandos = [];

this.comandos.push( new ComandoAgregar( receptor, 50 ) ); this.comandos.push( new ComandoAgregar( receptor, 20 ) ); this.comandos.push( new ComandoSustraer( receptor, 10 ) );}

// Invocador: ejecuta peticionesfunction Invocador ( comandos ) { var listaComandos = comandos;

this.ejecutar = function() { listaComandos.forEach( function ( comando ) { comando.ejecutar(); }); };

this.deshacerComandos = function ( numeroDeComandos ) { var i=0; for( /* i=0 */ ; i<numeroDeComandos; i++ ) { listaComandos.pop().deshacer(); } };}

// Ejemplo:var calculadora = new Calculadora(); // Receptorvar cliente = new Cliente(calculadora); // Clientevar invocador = new Invocador( cliente.comandos ); // Invocador

// Ejecución de comandos con interfaz común. Salida de consola:// 'Nueva valor: 50'// 'Nueva valor: 70'// 'Nueva valor: 60'invocador.ejecutar();

// Deshacer último comando. Salida: // 'Nueva valor: 70'invocador.deshacerComandos(1);

51

Page 52: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Aunque el código generado es complejo respecto a la tarea que propone (sumar y restar), es muy flexible yfácilmente extensible a través de nuevos comandos. Además, permite crear un historial de acciones, permitiendodeshacerlas en caso necesario.

52

Page 53: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Iterator

Propósito

Proporciona un modo de acceder secuencialmente a los elementos de un objeto agregado sin exponer surepresentación interna.

El punto de partida es un objeto que almacena información en una estructura compleja interna. Iteratorproporciona un método fácil para acceder secuencialmente a cada elemento de dicha estructura.

El "Cliente" que requiere acceder a los elementos de la estructura no necesita conocer la implementación de ésta;todo lo que necesita es acceder a los diferentes elementos individuales que la componen. Para ello, el objeto"Iterador" proporciona (entre otros) el método "siguiente", el cual devuelve el siguiente elemento consecutivo de laestructura. El patrón deja abierto el significado de "siguiente" en cada estructura, por lo que es decisión delprogramador interpretar qué debe devolver dicho método.

Iterator puede definir otros métodos auxiliares para recorrer los elementos de la estructura interna del objeto"Agregado", como por ejemplo

"haTerminado": Devuelve un valor booleano indicando si existen más elementos en la estructura."reiniciarIterador": reinicia el recorrido de la estructura, comenzando en el primer elemento."elementoActual": devuelve el elemento actual de la estructura

Separar el mecanismo de recorrido del objeto agregado permite definir iteradores con diferentesimplementaciones del método "siguiente", por lo que la misma estructura interna puede recorrerse en un ordendiferente según el iterador empleado.

El iterador y el objeto agregado están acoplados (iterador necesita conocer la estructura interna), mientras que elcliente únicamente conoce la interfaz Iterador (siguiente, haTerminado, etc.) y la forma de los elementos de laestructura.

Para promover la reutilización de código, el objeto agregado (el que contiene la estructura compleja) puedeimplementar el método "obtenerIterador", el cual devuelve el iterador con interfaz conocida por el cliente. De estemodo, cada subclase puede implementar su propio iterador concreto y proporcionarle al cliente una interfazconocida.

Implementación

53

Page 54: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Objeto agregadofunction MejoresCancionesDeRock() { // Estructura interna compleja var canciones = ['Kashmir', 'Stairway to Heaven', 'Smoke on the Water', 'Bohemian Rhapsody', 'Paranoid', 'Highway to Hell', 'Hotel California', 'Sultans of Swing', 'Dream on', 'Enter Sandman'];

// Interfaz Iterador implementado por MejoresCancionesDelRock this.obtenerIterador = function () {

var indiceActual = 0;

function siguiente() { if (haTerminado()) { return null; } return canciones[indiceActual++]; }

function haTerminado() { return indiceActual >= canciones.length; }

function reiniciar() { indiceActual = 0; }

function elementoActual() { return canciones[indiceActual]; }

return { siguiente: siguiente, haTerminado: haTerminado, reiniciar: reiniciar, elementoActual: elementoActual }; }};

// Ejemplo de uso

// Nuevo objeto agregadovar mejoresCancionesDeRock = new MejoresCancionesDeRock();

// Iterador asociadovar iterador = mejoresCancionesDeRock.obtenerIterador();

// Uso de interfaz Iterador para recorrer toda la estructura interna// Muestra el listado interno completowhile (!iterador.haTerminado()) { console.log(iterador.siguiente());}

// Reinicio del iteradoriterador.reiniciar();

// Obtener elemento actual (primer elemento tras el reinicio)console.log( iterador.elementoActual() ); // Muestra 'Kashmir'

54

Page 55: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Mediator

Propósito

Define un objeto que encapsula cómo interactúan un conjunto de objetos. Promueve un bajo acoplamientoal evitar que los objetos se refieran unos a otros explícitamente, y permite variar la interacción entre ellos deforma independiente.

Según la RAE, un mediador es aquel que "Actua entre dos o más partes para ponerlas de acuerdo en un pleito onegocio". De igual modo, el patrón Mediator permitirá que las diferentes partes del sistema se comuniquen através de un componente común, el "Mediador".

Imagine, a modo de ejemplo, un formulario web en el que la habilitación de unos campos dependerá de lasopciones previamente seleccionadas. Existirá, por tanto, dependencia entre los elementos del formulario. Si seencapsula el comportamiento colectivo de todos los elementos en un único objeto (el mediador), cadacomponente sólo tendrá que relacionarse con dicho objeto, evitando que unos objetos se refieran a otrosexplícitamente y reduciendo el número de interconexiones. Se pasa, pues, de una topología mallada a unatopología en estrella.

Aunque este patrón posee muchas similitudes con "Publish/Subscribe", son conceptualmente difeentes. Aunqueambos comunican a todos los elementos del escenario a través de un nuevo componente (llamado "canal" en elcaso del patrón Publish/Subscribe, y "mediador" en el patrón Mediator), el flujo de trabajo y la lógica de negocio esradicalmente diferente en cada patrón. Así, el "canal" actua como un bus de comunicaciones que traslada loseventos notificados por los "publicadores" a todos los subscriptores, siendo éstos quienes controlan la lógica denegocio de la aplicación. En cambio, el "mediador" centraliza por sí mismo toda la lógica de negocio y el flujo detrabajo, coordinando a los objetos del sistema e indicándoles las tareas que deben realizar en cada momento.

Por todo lo anterior, ambos patrones pueden incluso ser usados en conjunto usando Publis/Subscribe paracomunicar a todos los objetos con el "mediador" y viceversa, y "Mediator" para centrar la lógica de negocio y enviarlas acciones a los diferentes objetos a través del "canal" expuesto por el otro patrón.

Implementación

Suponga un juego en el que los jugadores tienen que acertar un número secreto, ganando quien acierte dichonúmero en primer lugar. Toda la información de la partida se muestra en un marcadar.

El siguiente código emplea la figura del "mediador" para interconectar a jugadores y marcador

// Colega: Jugadorfunction Jugador ( nombre ) { this.nombre = nombre; this.intentos = 0; this.juez = undefined;

this.jugar = function ( numero ){ if ( juez ) { this.intentos++; juez.nuevoIntento( this, numero ); } };}

// Colega: Marcadorfunction Marcador() {

// Actualizar marcador, mostrando el número de reintentos de cada jugador this.actualizar = function ( jugadores ) {

55

Page 56: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

jugadores.forEach(function ( jugador ){ console.log('Intentos fallidos de ' + jugador.nombre + ': ' + jugador.intentos); }); };

// Informar del ganador de la partida. this.mostrarGanador = function ( jugador ) { console.log('¡El jugador ' + jugador.nombre + ' ha ganado la partida!'); };}

// Mediador: Juezfunction Juez() {

// Listado de jugadores var jugadores = [];

// Referencia al Marcador var marcador;

// Número secreto. var numeroSecreto numeroSecreto = Math.floor((Math.random() * 10) + 1);

// A modo de demostración, fijaremos el número a un valor conocido. // Comentar para un juego real numeroSecreto = 3;

// Agregar jugadores a lal partida this.agregarJugador = function ( jugador ) { jugador.juez = this; jugadores.push(jugador); };

// Agregar marcador this.agregarMarcador = function ( nuevoMarcador ) { marcador = nuevoMarcador; }

// Permite a un jugador notificar de un nuevo intentos] this.nuevoIntento = function ( jugador, numero ) {

if ( numero == numeroSecreto) { marcador.mostrarGanador( jugador ); // ... Limpiar partida ... } else { marcador.actualizar( jugadores ); } };}

// Ejemplo de partidavar jugador1 = new Jugador('Juan');var jugador2 = new Jugador('Pedro');var marcador = new Marcador();var juez = new Juez();

// Establecer al objeto juez como árbitro de la partida // y controlador del marcadorjuez.agregarJugador(jugador1);juez.agregarJugador(jugador2);juez.agregarMarcador(marcador);

// Inicio del juego

// Muestra // 'Intentos fallidos de Juan: 1

56

Page 57: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Intentos fallidos de Pedro: 0''jugador1.jugar(1);

// Muestra // 'Intentos fallidos de Juan: 1// Intentos fallidos de Pedro: 1'jugador2.jugar(2);

// Muestra '¡El jugador Pedro ha ganado la partida!'jugador2.jugar(3);

Gracias a Mediador se ha centralizado la lógica de negocio en un solo elemento, disminuido el número deconexiones entre los mismos y, por tanto, reducido el acoplamiento entre los componentes del sistema.

57

Page 58: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Memento

Propósito

Representa y externaliza el estado interno de un objeto sin violar la encapsulación, de forma que éste puedevolver a dicho estado más tarde.

A veces es necesario implementar mecanismos de deshacer/rehacer que permitan a los usuario anular orecuperar operaciones. Para ello, el estado de los objetos en cada instante debe ser almacenado.

La solución más sencilla es exponer el estado de los objetos, esto es, hacer todas sus propiedades accesibles alresto de objetos. Pero este diseño rompe el principio de encapsulación, comprometiendo la fiabilidad de laaplicación.

Como alternativa, el patrón Memento guarda una instantánea del estado del objeto y ofrece una interfaz paracontrolar el acceso a dicha imagen, de forma que el objeto que captura el estado es el único con acceso total almismo. De esta forma, la encapsulación no se rompe completamente.

Aunque el patrón Command también tiene la habilidad de deshacer operaciones, solo es posible volver al estadooriginal cuando existe un comando inverso que anula las acciones del principal. Por ejemplo, una calculadoraimplementanda usando el patrón Command permite deshacer operaciones de suma y resta, pero no operacionesde elevar al cuadrado, pues durante el proceso se pierde el signo del operando original.

El patrón define los siguientes participantes:

Memento: guarda el estado del objeto "Creador". Protege el acceso a dicho estado a través de dos interfaces.La primera de ellas ofrece al exterior una versión reducida del estado. La segunda, en cambio, permite al"Creador" recuperar el estado completo.Creador: objeto que contiene el estado interno a capturar. Es quien origina el "Memento" (recuerdo) de suestado interno actual. Proporciona una interfaz para generar nuevas instantáneasConserje: Contiene el almacen de objetos "Memento" y permite el mecanismo de deshacer. Nunca operasobre el contenido de los objetos "Memento". En este patrón, tiene el roll de cliente.

El momento de creación de mementos depende de la aplicación. Puede interesar que un objeto genere nuevasinstantáneas cada vez que su estado interno cambia. En otras ocasiones, la captura del estado se realizará bajodemanda del Conserje.

Implementación

Una posible implementación que incluye protección de acceso al memento es:

// Clase Mementofunction Estado(propietario, fecha) {

// Encapsulación del estado var maquinaDelTiempo = propietario; var ubicacionTemporal = fecha;

// Protección de acceso this.recuperar = function (objeto) { if (objeto === maquinaDelTiempo) { return ubicacionTemporal; } else { return null; } };}

58

Page 59: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Creadorfunction MaquinaDelTiempo(fechaDePartida) {

// Estado interno var fechaActual = fechaDePartida;

// Crea un nuevo memento this.coordenadasTemporales = function () { return new Estado(this, fechaActual); };

// Recuperar memento this.regresar = function (estado) { var fechaDeRegreso = estado.recuperar(this); if (fechaDeRegreso) { fechaActual = fechaDeRegreso; console.log('Ha regresado a ' + fechaActual); } };

// Cambia el estado del creador. this.viajarA = function (fecha) { fechaActual = fecha; console.log('Ha viajado a ' + fechaActual); };}

// Conserjefunction Bitacora() {

// Mementos guardados var listadoDeViajes = [];

// Almacena un nuevo Memento this.anotar = function (datosDelViaje) { listadoDeViajes.push(datosDelViaje); };

// Recupera el último memento this.borrarUltimo = function () { return listadoDeViajes.pop(); };}

// Ejemplo de uso

// Nuevo "Creador" de tipo "Máquina del tiempo"var DeLorean = new MaquinaDelTiempo(2016);

// Nuevo Conserje de tipo "Bitácora"var bitacora = new Bitacora();

// Crear y almacenar el primer Mementobitacora.anotar(DeLorean.coordenadasTemporales());

// Cambio de estado interno: Primer viaje en el tiempoDeLorean.viajarA(1955); // Muestra 'Ha viajado a 1955'

// Recuperar Memento: Regreso al futuroDeLorean.regresar(bitacora.borrarUltimo()); // Muestra 'Ha regresado a 2016'

Cabe destacar que aunque los métodos definidos se han nombrado teniendo en cuenta la semántica de laaplicación, se ha generado un comentario en cada línea para mostrar la asociación entre cada elemento y loscolaboradores genéricos del patrón Memento.

59

Page 60: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Observer

Propósito

Define una dependencia de uno-a-muchos entre objetos, de forma que cuando un objeto cambie de estadose notifica y se actualizan automáticamente todos los objetos que dependen de él.

El patrón observador permite a un objeto (conocido como "Sujeto") mantener una lista de objetos (denominados"observadores") que dependen de él, notificándolos de cualquier cambio en su estado. Para propiciar lareutilización del código, es necesario que el diseño permita un bajo acoplamiento entre todos los participantes.

En primer lugar los observadores se registran en el sujeto a través de la función "agregar" que éste publica.Cuando el sujeto necesite informar a los observadores de cualquier suceso, retransmite una notificación a losobservadores a través del método público "actualizar" que éstos exponen. Por último, cuando un observador lodesea, puede darse "desconectarse" del sujeto a través de la función "quitar".

Esta patrón es ampliamente usado en javascript cuando se emplea en aplicaciones Web, pues facilita la gestiónde acciones en respuesta a eventos del usuario (por ejemplo, pulsaciones de ratón, teclado, etc. son escuchadaspor la aplicación para actuar en consecuencia).

Implementación

A continuación se muestra el código necesario para crear los objetos colaboradores "Sujeto" y "Observador", asícomo un ejemplo de uso.

60

Page 61: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Sujeto. // Puede agregar, eliminar y notificar a los observadores de su lista.function Sujeto(){ this.listaObservadores = []; // Listado de observadores}

Sujeto.prototype.agregarObservador = function (observador) { this.listaObservadores.push(observador);}

Sujeto.prototype.quitarObservador = function (observador) { // Si el observador se encuentra en la lista, eliminar de ella. var indiceObservador = this.listaObservadores.indexOf( observador ); if( indiceObservador != -1 ) { this.listaObservadores.splice( indiceObservador, 1 ); }}

Sujeto.prototype.notificarAObservadores = function ( mensaje ) { this.listaObservadores.forEach( function( observador ) { observador.actualizar( mensaje ); } ); }

// Observador. // Recibe notificaciones del Sujeto a través de la función "actualizar"function Observador(nombre) { this.nombre = nombre; this.actualizar = function ( mensaje ) { console.log( nombre + ' ha recibido un mensaje. Contenido: ' + mensaje ); };

// Funciones auxiliares para que Observador pueda decidir // cuándo registrarse a un Sujeto o anular dicho registro. this.observarA = function( sujeto ) { sujeto.agregarObservador( this ); };

this.dejarDeObservarA = function( sujeto ) { sujeto.quitarObservador ( this ); };}

// Escenario de ejemplo: 1 sujeto y dos observadores suscritosvar sujeto = new Sujeto();var observador1 = new Observador( 'Observador 1' );var observador2 = new Observador( 'Observador 2' );

observador1.observarA( sujeto );observador2.observarA( sujeto );

// Notificar cambio de estado.// Salida de la consola:// Observador 1 ha recibido un mensaje. Contenido: mensaje de echo// Observador 2 ha recibido un mensaje. Contenido: mensaje de echosujeto.notificarAObservadores( 'mensaje de echo' );

// Eliminar a observador 1;observador1.dejarDeObservarA( sujeto );

// Notificación al resto de observadores. Salida de la consola:// Observador 2 ha recibido un mensaje. Contenido: observador 2 eliminadosujeto.notificarAObservadores( 'observador 2 eliminado' );

El patrón Observer requiere que el objeto Observador se suscriba al objeto Sujeto, por lo que se requierevisibilidad entre ambos, con la consecuente dependencia entre ellos.

61

Page 62: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Como alternativa, el patrón Publish/Subscribe, establece un canal de comunicaciones intermedio que desacoplaa Sujeto y Observador, conectando a todos los objetos interesados a una interfaz común en la que puedenintercambiar información. Cualquier objeto puede, por tanto, publicar información en el canal o suscribirse al canalpara recibir dicha información. Puede encontrar una implementación de éste patrón en el repositorio Github deAddy Osmani (https://github.com/addyosmani/pubsubz).

62

Page 63: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Template Method

Propósito

Define en una operación el esqueleto de un algoritmo, delegando en las subclases algunos de sus pasos.Permite que las subclases redefinan ciertos pasos del algoritmo sin cambiar su estructura.

El patrón define un algoritmo en términos de operaciones abstractas junto con una implementación inicial de lasmismas. Cualquier subclase que implemente la interfaz del algoritmo puede sobreescribir el comportamiento decualquiera de las operaciones.

En la programación orientada a objetos basada en clases, la herencia proporciona este mecanismo. Enjavascript, puede ser implementado a través de la herencia por prototipos.

Implementación

Una posible definición de un algoritmo que comunica dos equipos consta de los siguientes pasos:

1. Reservar recursos del equipo.2. Iniciar llamada.

Depende del protocolo de comunicaciones3. Enviar información.

Depende del protoco de comunicaciones.4. Finalizar llamada

5. Liberar recursos del ordenador.

Los pasos 1 y 5 dependen del hardware del equipo y de las capas físicas y de enlace, mientras que los pasos 2,3y 4 dependen del protocolo de comunicaciones a implementar. Cualquier equipo que implemente el algoritmodeberá, por tanto, reimplementar estos pasos para adecuarlos a sus características y al protocolo elegido.

63

Page 64: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

// Plantilla genérica del algoritmofunction Comunicacion( nombreEquipo) { this.nombre = nombreEquipo;}

// Interfaz del algoritmoComunicacion.prototype.reservarRecursos = function ( parametros ) { console.log( 'Recursos reservados'); };

Comunicacion.prototype.iniciarLlamada = function ( equipo ) { console.log( 'Conexión establecida con: ' + equipo.nombre );};

Comunicacion.prototype.enviarInformacion = function ( mensaje ) { console.log( 'Información enviada: ' + mensaje ); };

Comunicacion.prototype.finalizarLLamada = function () { console.log( 'Llamada finalizada' ); };

Comunicacion.prototype.liberarRecursos = function () { console.log( 'Recursos Liberados' ); };

// Objeto que implementa el algoritmo:// Extender ComunicacionArduino usando la interfaz Comunicacionfunction ComunicacionArduino( nombre ) { this.nombre = nombre;}ComunicacionArduino.prototype = Object.create(Comunicacion.prototype);ComunicacionArduino.prototype.constructor = ComunicacionArduino;

// Reimplementar pasos específicos de arduinoComunicacionArduino.prototype.reservarRecursos = function () { console.log( 'Arduino: Recursos reservados' );};

ComunicacionArduino.prototype.liberarRecursos = function () { console.log( 'Arduino: Recursos Liberados' );};

// Ejemplo de uso

// Objetos con algoritmo concretovar equipo1 = new ComunicacionArduino('Arduino Nano');var equipo2 = new ComunicacionArduino('Arduino Mega');

// Ejecución del algoritmo concretoequipo1.reservarRecursos(); // Muestra 'Arduino: Recursos reservados'equipo1.iniciarLlamada(equipo2); // Muestra Conexión establecida con Arduino Mega'equipo1.enviarInformacion('echo'); // Muestra 'Información enviada: echo'equipo1.finalizarLLamada(); // Muestra 'Llamada finalizada'equipo1.liberarRecursos(); // Muestra 'Arduino: Recursos liberados'

64

Page 65: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Module

Propósito

Separar y organizar la funcionalidad total de un programa en modulos independientes e intercambiables.

Cada módulo contiene todo lo necesario para ejecutar un sólo aspecto de la funcionalidad deseada. Además,establece una interfaz pública con el exterior, ocultando detalles de implementación y facilitando la encapsulacióndel código y su reusabilidad.

El patrón Module puede considerarse creacional y estructural, pues gestiona la creación, organización yagrupación de otros elementos.

Implementación

El siguiente código puede emplearse como plantilla para crear un módulo en Javascript:

var modulo1 = (function () {

// Variables privadas var contador = 0;

// Funciones privadas log = function (msg) { console.log(msg); };

return {

// Variables públicas nombreModulo: "miModulo",

// Funciones públicas incrementarContador: function () { contador++; }, reiniciarContador: function () { contador = 0; }, imprimirContador: function () { log(contador); } };})();

modulo1.incrementarContador(); // Contador = 1;modulo1.imprimirContador(); // Muestra '1'modulo1.reiniciarContador(); // Contador = 0;

El ámbito de las variables y funciones incluídas en el módulo queda definido por la función anónima que envuelvea todo el código, la cual es ejecutada inmediatamente quedando, por tanto, inaccesible desde el ámbito global.Como consecuencia, "modulo1" encapsula variables y funciones privadas y públicas, sirviendo de espacio denombres.

Además, es posible emplear el patrón para devolver diferentes funciones/variables dependiendo del entornodonde se inicializa el módulo.

Puede encontrar más información sobre el patrón Module en la página personal de Todd Motto(https://toddmotto.com/mastering-the-module-pattern/)

65

Page 66: Tabla de contenido - bibing.us.esbibing.us.es/proyectos/abreproy/12355/fichero/ANEXO_A.pdf( Object-Oriented JavaScript. Create scalable, reusable high-quality JavaScript applications

Revealing Module

Propósito

Separar y organizar la funcionalidad total de un programa en modulos independientes e intercambiables.

Se trata de una variación del patrón Module en la que todas las funciones y variables se definen privadas paraposteriormente publicar sólo aquellas de interés.

Implementación

A continuación se muestra un módulo implementado usando el patrón "Revealing Module":

var revealingModule = (function () {

// Variables - Inicialmente privadas var variable1 = 1; var variable2 = 2;

// Funciones - Inicialmente privadas function funcion1() { console.log('Funcion 1'); }

function funcion2() { console.log('Funcion 2'); }

// Referencias públicas a funciones y propiedades privadas return { variablePublica: variable1, funcionPublica: funcion1 };

})();

revealingModule.funcionPublica(); // Muestra 'Funcion 1'revealingModule.variablePublica; // Muestra '1'

En el ejemplo anterior destaca la claridad con la que se define el módulo. Como contrapartida, si una funciónprivada hace referencia a una pública que posteriormente se sobreescribe, entonces la función privada seguiráreferenciando a la implementación privada, por lo que no empleará la nueva definición. Como resultado, el diseñopuede considerarse más frágil que el patrón "Module".

66