Ejemplos de patrones prácticos de diseño orientado a objetos de JavaScript

81

¿Qué patrones de diseño orientado a objetos utiliza en el javascript de su aplicación y por qué?

Siéntase libre de publicar código, incluso si no hay un patrón de diseño formal adjunto.

He escrito mucho javascript, pero no he aplicado muchos patrones orientados a objetos a lo que estoy haciendo, y estoy seguro de que me faltan muchos.

ming yeow
fuente
Probablemente no hayas visto POO clásica en el sentido que piensas. Sin embargo, probablemente haya utilizado funciones con OOP prototípico y nunca se haya dado cuenta.
dave
De hecho, (a veces) me doy cuenta de que cuando estoy usando POO, quiero empezar a usar POO de forma mucho más consciente, precisamente porque quiero ser mucho más deliberado al respecto
ming yeow
Voy a votar para cerrar esta pregunta como fuera de tema porque solo pide una lista de cosas que otras personas hacen en su código.
Almo

Respuestas:

54

Los siguientes son tres patrones de JavaScript populares. Estos resultan ser fácilmente implementables debido a cierres :

Es posible que también desee consultar:

La siguiente es una charla de Google I / O de 2008 presentada por Díaz, donde analiza algunos temas de su libro:

Daniel Vassallo
fuente
¡bonito! curry parece una forma más inteligente de hacer algunas de las generalizaciones que estaba tratando de hacer. ya estoy usando formas simples de módulo y memorización, pero necesito estudiar estos ejemplos para impulsar cómo lo hago actualmente. ¿Cuáles usas más?
ming yeow
@ming: Probablemente, es el patrón del módulo. Muy fácil de implementar y comprender, y viene con algunas características interesantes, que incluyen espacios de nombres y variables / métodos privados.
Daniel Vassallo
26

Herencia

Utilizo una notación para la herencia que se basa en ExtJS 3 , que encuentro que funciona bastante cerca de emular la herencia clásica en Java. Básicamente se ejecuta de la siguiente manera:

// Create an 'Animal' class by extending
// the 'Object' class with our magic method
var Animal = Object.extend(Object, {
    move : function() {alert('moving...');}
});

// Create a 'Dog' class that extends 'Animal'
var Dog = Object.extend(Animal, {
    bark : function() {alert('woof');}
});

// Instantiate Lassie
var lassie = new Dog();

// She can move and bark!
lassie.move();
lassie.bark();

Espacios de nombres

También estoy de acuerdo con Eric Miraglia en ceñirse a los espacios de nombres, por lo que el código anterior debe ejecutarse dentro de su propio contexto fuera del objeto de la ventana, esto es fundamental si desea que su código se ejecute como uno de los muchos marcos / bibliotecas concurrentes que se ejecutan en la ventana del navegador.

Esto significa que la única forma de acceder al objeto de ventana es a través de su propio espacio de nombres / objeto de módulo:

// Create a namespace / module for your project
window.MyModule = {};

// Commence scope to prevent littering 
// the window object with unwanted variables
(function() {

    var Animal = window.MyModule.Animal = Object.extend(Object, {
         move: function() {alert('moving...');}
    });

    // .. more code

})();

Interfaces

También puede hacer uso de construcciones OOP más avanzadas, como interfaces, para mejorar el diseño de su aplicación. Mi enfoque para estos es mejorar el Function.prototypepara obtener una notación en estas líneas:

var Dog = Object.extend(Animal, {
     bark: function() {
         alert('woof');
     }
     // more methods ..
}).implement(Mammal, Carnivore);

Patrones OO

En cuanto a los 'Patrones' en el sentido de Java, solo he encontrado uso para el patrón Singleton (excelente para el almacenamiento en caché) y el patrón Observer para la funcionalidad basada en eventos, como asignar algunas acciones cuando un usuario hace clic en un botón.

Un ejemplo de la utilización del patrón de observador sería:

// Instantiate object
var lassie = new Animal('Lassie');

// Register listener
lassie.on('eat', function(food) {
   this.food += food;
});

// Feed lassie by triggering listener
$('#feeding-button').click(function() {
    var food = prompt('How many food units should we give lassie?');
    lassie.trigger('eat', [food]);
    alert('Lassie has already eaten ' + lassie.food + ' units');
});

Y eso es solo un par de trucos en mi bolsa de OO JS, espero que te sean útiles.

Le recomiendo que, si tiene la intención de seguir este camino, lea Douglas Crockfords Javascript: the Good Parts . Es un libro brillante para estas cosas.

Steven de Salas
fuente
20

Soy fanático del Module Pattern . Es una forma de implementar marcos extensibles, no dependientes (la mayoría de las veces).

Ejemplo:

El marco, Qse define así:

var Q = {};

Para agregar una función:

Q.test = function(){};

Estas dos líneas de código se utilizan juntas para formar módulos . La idea detrás de los módulos es que todos ellos extienden algún marco base, en este caso Q, pero no dependen unos de otros (si están diseñados correctamente) y pueden incluirse en cualquier orden.

En un módulo, primero crea el objeto de marco si no existe (que es un ejemplo del patrón Singleton ):

if (!Q)
    var Q = {};

Q.myFunction = function(){};

De esa manera, puede tener varios módulos (como el anterior) en archivos separados e incluirlos en cualquier orden. Cualquiera de ellos creará el objeto marco y luego lo extenderá. No es necesario comprobar manualmente si el marco existe. Luego, para verificar si existe un módulo / función en código personalizado:

if (Q.myFunction)
    Q.myFunction();
else
    // Use a different approach/method
Chris Laplante
fuente
1
Esto parece extremadamente útil. ¿cómo estás usando esto en tu código? ¡gracias por compartir!
ming yeow
Lo usé en un proyecto reciente que hice en el que tenía archivos JavaScript separados para las funciones comunes, la interfaz de usuario y otros dos mecanismos especializados. Todos los archivos agregaron funciones al mismo marco (definido usando el método que mostré arriba) y llamaron a las funciones como lo hice anteriormente.
Chris Laplante
Uno de los principales usos de este tipo de técnica es evitar la contaminación del espacio de nombres global. ¿Qué contamina más? ¿Una sola Qvariable de marco o docenas y docenas de funciones y variables?
Chris Laplante
6

El patrón singleton es a menudo muy útil para cosas de "encapsulación" y organización. Incluso puedes cambiar la accesibilidad.

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

forma más limpia de implementar un singleton en javascript

Gordon Gustafson
fuente
impresionante - ¡Este es el que uso todo el tiempo! Pero eso es solo el alcance de mi javascript OO. ;)
ming yeow
4

Realmente me gusta el patrón de encadenamiento de métodos de jquery , que le permite llamar a varios métodos en un objeto. Hace que sea realmente fácil realizar varias operaciones en una sola línea de código.

Ejemplo:

$('#nav').click(function() {
   $(this).css('color','#f00').fadeOut();
});
GSto
fuente
correcto - de acuerdo! ¿Ha desarrollado sus propios métodos personalizados que funcionan de esta manera antes?
ming yeow
3

Realmente me gusta el patrón Decorator con complementos de jQuery. En lugar de modificar los complementos para satisfacer sus necesidades, escriba un complemento personalizado que solo reenvíe solicitudes y agregue parámetros y funciones adicionales.

Por ejemplo, si necesita pasar un conjunto de argumentos predeterminados todo el tiempo, y necesita un comportamiento ligeramente diferente que se relacione con la lógica empresarial, escriba un complemento que haga lo que sea necesario prey postfuncione para satisfacer sus necesidades y transmita sus argumentos predeterminados si esos argumentos particulares no se especifican.

El principal beneficio de esto es que puede actualizar sus bibliotecas y no preocuparse por portar cambios en la biblioteca. Su código puede romperse, pero existe al menos la posibilidad de que no lo haga.

Stefan Kendall
fuente
Suena como una buena idea. ¿Tiene un ejemplo real en el código para hacer la extensión real? Incluso un simple ejemplo ayudará mucho a todos.
ming yeow
3

Uno de los patrones útiles en el mundo de JavaScript es el patrón de encadenamiento que LINQ hizo popular en primer lugar, y también se usa en jQuery.

este patrón nos permite llamar a diferentes métodos de una clase de manera encadenada.

la estructura principal de este patrón sería como

var Calaculator = function (init) {
    var result = 0;
    this.add = function (x) { result += (init + x); return this; };
    this.sub = function (x) { result += (init - x); return this; };
    this.mul = function (x) { result += (init * x); return this; };
    this.div = function (x) { result += (init / x); return this; };

    this.equals = function (callback) {
        callback(result);
    }

    return this;
};


new Calaculator(0)
    .add(10)
    .mul(2)
    .sub(5)
    .div(3)
    .equals(function (result) {
        console.log(result);
    });

la idea clave de este patrón es la thispalabra clave, que posibilita el acceso a otro miembro público de la función Calculadora.

Matrix Buster
fuente