Sök…
Introduktion
Designmönster är ett bra sätt att hålla din kod läsbar och torka. Torkar står för inte upprepa dig själv . Nedan kan du hitta fler exempel på de viktigaste designmönstren.
Anmärkningar
Inom mjukvaruteknik är ett mönster för mjukvarudesign en allmän återanvändbar lösning på ett vanligt förekommande problem inom ett givet sammanhang inom mjukvarudesign.
Singletonmönster
Singleton-mönstret är ett designmönster som begränsar inställningen av en klass till ett objekt. När det första objektet har skapats, kommer det att returnera referensen till samma när det krävs ett objekt.
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;
}
};
})();
Användande:
// 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
Modul och avslöjande modulmönster
Modulmönster
Modulmönstret är ett kreativt och strukturellt designmönster som ger ett sätt att kapsla in privata medlemmar medan de producerar ett offentligt API. Detta åstadkoms genom att skapa en IIFE som tillåter oss att definiera variabler som endast är tillgängliga inom dess omfattning (genom stängning ) medan vi returnerar ett objekt som innehåller det offentliga API: et.
Detta ger oss en ren lösning för att dölja huvudlogiken och bara avslöja ett gränssnitt som vi önskar att andra delar av vår applikation ska använda.
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 */);
Avslöjande modulmönster
Det avslöjande modulmönstret är en variant i modulmönstret. De viktigaste skillnaderna är att alla medlemmar (privata och offentliga) definieras inom stängningen, returvärdet är ett bokstavligt objekt som inte innehåller några funktionsdefinitioner, och alla referenser till medlemsdata görs genom direkta referenser snarare än genom det returnerade objektet.
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 */);
Avslöjande prototypmönster
Denna variation av det avslöjande mönstret används för att separera konstruktören till metoderna. Det här mönstret tillåter oss att använda javascript-språket som ett objektorienterat språk:
//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}
}();
Den här koden ovan bör finnas i en separat fil .js som ska refereras till på vilken sida som behövs. Det kan användas så här:
var menuActive = new NavigationNs.active('ul.sidebar-menu li', 5);
menuActive.setCurrent();
Prototypmönster
Prototypmönstret fokuserar på att skapa ett objekt som kan användas som en plan för andra objekt genom prototyparv. Det här mönstret är i sig naturligt lätt att arbeta med i JavaScript på grund av det ursprungliga stödet för prototypformad arv i JS vilket innebär att vi inte behöver spendera tid eller ansträngningar för att imitera denna topologi.
Skapa metoder på prototypen
function Welcome(name) {
this.name = name;
}
Welcome.prototype.sayHello = function() {
return 'Hello, ' + this.name + '!';
}
var welcome = new Welcome('John');
welcome.sayHello();
// => Hello, John!
Prototypisk ärft
Arv från ett "föräldraobjekt" är relativt enkelt via följande mönster
ChildObject.prototype = Object.create(ParentObject.prototype);
ChildObject.prototype.constructor = ChildObject;
Där ParentObject
är det objekt du vill ärva de prototypade funktionerna från, och ChildObject
är det nya objektet du vill sätta dem på.
Om förälderobjektet har värden som det initialiseras i sin konstruktör måste du ringa föräldrakonstruktören när du initialiserar barnet.
Du gör det med följande mönster i ChildObject
konstruktören.
function ChildObject(value) {
ParentObject.call(this, value);
}
Ett komplett exempel där ovanstående implementeras
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!
Fabriksfunktioner
En fabriksfunktion är helt enkelt en funktion som returnerar ett objekt.
Fabriksfunktioner kräver inte användning av det new
nyckelordet, men kan fortfarande användas för att initialisera ett objekt, som en konstruktör.
Ofta används fabriksfunktioner som API-omslag, som i fallet med jQuery och moment.js , så användarna behöver inte använda new
.
Följande är den enklaste formen av fabriksfunktion; ta argument och använda dem för att skapa ett nytt objekt med objektet bokstavligt:
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"
Det är lätt att definiera privata egenskaper och metoder i en fabrik genom att inkludera dem utanför det returnerade objektet. Detta håller dina implementeringsdetaljer inkapslade, så att du bara kan exponera det offentliga gränssnittet för ditt objekt.
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
Den sista raden kommer att ge ett fel eftersom funktionsformellt formalName
är stängt i cowFactory
funktionen. Detta är en stängning .
Fabriker är också ett bra sätt att tillämpa funktionella programmeringsmetoder i JavaScript, eftersom de är funktioner.
Fabrik med komposition
"Föredrar komposition framför arv" är en viktig och populär programmeringsprincip som används för att tilldela beteenden till objekt, i motsats till att ärva många ofta onödiga beteenden.
Beteende fabriker
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');
}
};
};
Objektfabriker
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)
);
};
Användande
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
Abstrakt fabriksmönster
Det abstrakta fabriksmönstret är ett kreativt designmönster som kan användas för att definiera specifika instanser eller klasser utan att behöva ange det exakta objektet som skapas.
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 )