Buscar..


Introducción

Los patrones de diseño son una buena manera de mantener su código legible y SECO. DRY significa no repetirte a ti mismo . A continuación puede encontrar más ejemplos sobre los patrones de diseño más importantes.

Observaciones

En ingeniería de software, un patrón de diseño de software es una solución general reutilizable a un problema que ocurre comúnmente dentro de un contexto dado en el diseño de software.

Patrón Singleton

El patrón Singleton es un patrón de diseño que restringe la creación de instancias de una clase a un objeto. Una vez creado el primer objeto, devolverá la referencia al mismo siempre que se llame para un objeto.

var Singleton = (function () {
        // instance stores a reference to the Singleton
        var instance;
    
        function createInstance() {
            // private variables and methods
            var _privateVariable = 'I am a private variable';
            function _privateMethod() {
                console.log('I am a private method');
            }

            return {
                // public methods and variables
                publicMethod: function() {
                    console.log('I am a public method');
                },
                publicVariable: 'I am a public variable'
            };
        }
         
        return {
            // Get the Singleton instance if it exists
            // or create one if doesn't
            getInstance: function () {
                if (!instance) {
                    instance = createInstance();
                }
                return instance;
            }
        };
    })();

Uso:

// there is no existing instance of Singleton, so it will create one
var instance1 = Singleton.getInstance();
// there is an instance of Singleton, so it will return the reference to this one
var instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true

Módulo y patrones de módulos reveladores

Patrón del módulo

El patrón del Módulo es un patrón de diseño creacional y estructural que proporciona una manera de encapsular miembros privados mientras se produce una API pública. Esto se logra creando un IIFE que nos permite definir variables solo disponibles en su alcance (a través del cierre ) mientras se devuelve un objeto que contiene la API pública.

Esto nos da una solución limpia para ocultar la lógica principal y solo exponer una interfaz que deseamos que usen otras partes de nuestra aplicación.

var Module = (function(/* pass initialization data if necessary */) {
  // Private data is stored within the closure
  var privateData = 1;

  // Because the function is immediately invoked,
  // the return value becomes the public API
  var api = {
    getPrivateData: function() {
      return privateData;
    },
    
    getDoublePrivateData: function() {
      return api.getPrivateData() * 2;
    }
  };
  return api;
})(/* pass initialization data if necessary */);

Módulo de Módulo Revelador

El patrón del módulo revelador es una variante en el patrón del módulo. Las diferencias clave son que todos los miembros (privados y públicos) se definen dentro del cierre, el valor de retorno es un objeto literal que no contiene definiciones de funciones, y todas las referencias a los datos de los miembros se realizan a través de referencias directas en lugar de a través del objeto devuelto.

var Module = (function(/* pass initialization data if necessary */) {
  // Private data is stored just like before
  var privateData = 1;

  // All functions must be declared outside of the returned object
  var getPrivateData = function() {
    return privateData;
  };

  var getDoublePrivateData = function() {
    // Refer directly to enclosed members rather than through the returned object
    return getPrivateData() * 2;
  };

  // Return an object literal with no function definitions
  return {
    getPrivateData: getPrivateData,
    getDoublePrivateData: getDoublePrivateData
  };
})(/* pass initialization data if necessary */);

Patrón de prototipo revelador

Esta variación del patrón revelador se utiliza para separar el constructor de los métodos. Este patrón nos permite usar el lenguaje javascript como un lenguaje orientado a objetos:

//Namespace setting
var NavigationNs = NavigationNs || {};

// This is used as a class constructor 
NavigationNs.active = function(current, length) {        
    this.current = current;
    this.length = length;
}

// The prototype is used to separate the construct and the methods    
NavigationNs.active.prototype = function() {
    // It is a example of a public method because is revealed in the return statement
    var setCurrent = function() {
        //Here the variables current and length are used as private class properties  
        for (var i = 0; i < this.length; i++) {                
                $(this.current).addClass('active');                 
        }
    }
    return { setCurrent: setCurrent };
}();

// Example of parameterless constructor  
NavigationNs.pagination = function() {}

NavigationNs.pagination.prototype = function() {
// It is a example of a private method because is not revealed in the return statement
    var reload = function(data) {
        // do something
    },
    // It the only public method, because it the only function referenced in the return statement
     getPage = function(link) {
        var a = $(link);

        var options = {url: a.attr('href'), type: 'get'}
        $.ajax(options).done(function(data) {            
           // after the the ajax call is done, it calls private method
           reload(data);
        });

        return false;
    }
    return {getPage : getPage}
}();

Este código de arriba debe estar en un archivo .js separado para ser referenciado en cualquier página que sea necesaria. Se puede usar así:

var menuActive = new NavigationNs.active('ul.sidebar-menu li', 5);
menuActive.setCurrent();

Patrón prototipo

El patrón de prototipo se centra en crear un objeto que se puede utilizar como modelo para otros objetos a través de la herencia prototípica. Es inherentemente fácil trabajar con este patrón en JavaScript debido al soporte nativo para la herencia prototípica en JS, lo que significa que no necesitamos gastar tiempo ni esfuerzo en imitar esta topología.


Creación de métodos sobre el prototipo.

function Welcome(name) {
  this.name = name;
}
Welcome.prototype.sayHello = function() {
  return 'Hello, ' + this.name + '!';
}

var welcome = new Welcome('John');

welcome.sayHello();
// => Hello, John!

Herencia prototípica

La herencia de un 'objeto principal' es relativamente fácil a través del siguiente patrón

ChildObject.prototype = Object.create(ParentObject.prototype);
ChildObject.prototype.constructor = ChildObject;

Donde ParentObject es el objeto del que desea heredar las funciones prototipadas, y ChildObject es el nuevo Objeto en el que desea ponerlas.

Si el objeto padre tiene valores, se inicializa en su constructor, debe llamar al constructor padre al inicializar el hijo.

Lo haces usando el siguiente patrón en el constructor ChildObject .

function ChildObject(value) {
    ParentObject.call(this, value);
}

Un ejemplo completo donde se implementa lo anterior.

function RoomService(name, order) {
  // this.name will be set and made available on the scope of this function
  Welcome.call(this, name);
  this.order = order;
}

// Inherit 'sayHello()' methods from 'Welcome' prototype
RoomService.prototype = Object.create(Welcome.prototype);

// By default prototype object has 'constructor' property. 
// But as we created new object without this property  -  we have to set it manually,
// otherwise 'constructor' property will point to 'Welcome' class
RoomService.prototype.constructor = RoomService;

RoomService.prototype.announceDelivery = function() {
  return 'Your ' + this.order + ' has arrived!';
}
RoomService.prototype.deliverOrder = function() {
  return this.sayHello() + ' ' + this.announceDelivery();
}

var delivery = new RoomService('John', 'pizza');

delivery.sayHello();
// => Hello, John!,

delivery.announceDelivery();
// Your pizza has arrived!

delivery.deliverOrder();
// => Hello, John! Your pizza has arrived!

Funciones de Fábrica

Una función de fábrica es simplemente una función que devuelve un objeto.

Las funciones de fábrica no requieren el uso de la new palabra clave, pero aún se pueden usar para inicializar un objeto, como un constructor.

A menudo, las funciones de fábrica se utilizan como envoltorios de API, como en los casos de jQuery y moment.js , por lo que los usuarios no necesitan usar new .

La siguiente es la forma más simple de función de fábrica; tomando argumentos y usándolos para crear un nuevo objeto con el objeto literal:

function cowFactory(name) {
    return {
        name: name,
        talk: function () {
            console.log('Moo, my name is ' + this.name);
        },
    };
}

var daisy = cowFactory('Daisy');  // create a cow named Daisy
daisy.talk();  // "Moo, my name is Daisy"

Es fácil definir propiedades y métodos privados en una fábrica, incluyéndolos fuera del objeto devuelto. Esto mantiene los detalles de su implementación encapsulados, por lo que solo puede exponer la interfaz pública a su objeto.

function cowFactory(name) {
    function formalName() {
        return name + ' the cow';
    }

    return {
        talk: function () {
            console.log('Moo, my name is ' + formalName());
        },
    };
}

var daisy = cowFactory('Daisy');
daisy.talk();  // "Moo, my name is Daisy the cow"
daisy.formalName();  // ERROR: daisy.formalName is not a function

La última línea dará un error porque la función formalName está cerrada dentro de la función cowFactory . Esto es un cierre .

Las fábricas también son una excelente manera de aplicar prácticas de programación funcional en JavaScript, ya que son funciones.

Fábrica con Composición

"Preferir la composición sobre la herencia" es un principio de programación importante y popular, que se utiliza para asignar comportamientos a los objetos, en lugar de heredar muchos comportamientos a menudo innecesarios.

Fábricas de comportamiento

var speaker = function (state) {
    var noise = state.noise || 'grunt';

    return {
        speak: function () {
            console.log(state.name + ' says ' + noise);
        }
    };
};

var mover = function (state) {
    return {
        moveSlowly: function () {
            console.log(state.name + ' is moving slowly');
        },
        moveQuickly: function () {
            console.log(state.name + ' is moving quickly');
        }
    };
};

Fábricas de objetos

6
var person = function (name, age) {
    var state = {
        name: name,
        age: age,
        noise: 'Hello'
    };

    return Object.assign(     // Merge our 'behaviour' objects
        {},
        speaker(state),
        mover(state)
    );
};

var rabbit = function (name, colour) {
    var state = {
        name: name,
        colour: colour
    };

    return Object.assign(
        {},
        mover(state)
    );
};

Uso

var fred = person('Fred', 42);
fred.speak();        // outputs: Fred says Hello
fred.moveSlowly();   // outputs: Fred is moving slowly

var snowy = rabbit('Snowy', 'white');
snowy.moveSlowly();  // outputs: Snowy is moving slowly
snowy.moveQuickly(); // outputs: Snowy is moving quickly
snowy.speak();       // ERROR: snowy.speak is not a function

Patrón abstracto de la fábrica

El Abstract Factory Pattern es un patrón de diseño creativo que se puede usar para definir instancias o clases específicas sin tener que especificar el objeto exacto que se está creando.

function Car() { this.name = "Car"; this.wheels = 4; }
function Truck() { this.name = "Truck"; this.wheels = 6; }
function Bike() { this.name = "Bike"; this.wheels = 2; }

const vehicleFactory = {
    createVehicle: function (type) {
        switch (type.toLowerCase()) {
            case "car":
                return new Car();
            case "truck":
                return new Truck();
            case "bike":
                return new Bike();
            default:
                return null;
        }
    }
};

const car = vehicleFactory.createVehicle("Car"); // Car { name: "Car", wheels: 4 }  
const truck = vehicleFactory.createVehicle("Truck"); // Truck { name: "Truck", wheels: 6 }  
const bike = vehicleFactory.createVehicle("Bike"); // Bike { name: "Bike", wheels: 2 }  
const unknown = vehicleFactory.createVehicle("Boat"); // null ( Vehicle not known )


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow