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
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 )