Suche…
Einführung
Entwurfsmuster sind eine gute Möglichkeit, Ihren Code lesbar und trocken zu halten. DRY steht für sich nicht wiederholen . Nachfolgend finden Sie weitere Beispiele zu den wichtigsten Entwurfsmustern.
Bemerkungen
Beim Software-Engineering ist ein Software-Entwurfsmuster eine allgemein wiederverwendbare Lösung für ein häufig auftretendes Problem in einem bestimmten Kontext des Software-Designs.
Singleton-Muster
Das Singleton-Muster ist ein Entwurfsmuster, das die Instantiierung einer Klasse auf ein Objekt beschränkt. Nachdem das erste Objekt erstellt wurde, wird bei jedem Aufruf eines Objekts die Referenz auf dasselbe Objekt zurückgegeben.
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;
}
};
})();
Verwendungszweck:
// 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 und aufschlussreiche Modulmuster
Modulmuster
Das Modulmuster ist ein kreatives und strukturelles Entwurfsmuster, mit dem private Mitglieder gekapselt werden können, während eine öffentliche API erstellt wird. Dies wird erreicht, indem ein IIFE erstellt wird, mit dem Variablen definiert werden können, die nur in seinem Bereich (durch Schließen ) verfügbar sind, während ein Objekt zurückgegeben wird, das die öffentliche API enthält.
Dies gibt uns eine saubere Lösung, um die Hauptlogik zu verbergen und nur eine Schnittstelle bereitzustellen, die andere Teile unserer Anwendung verwenden sollen.
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 */);
Muster-Muster aufdecken
Das Mustermuster des aufschlussreichen Moduls ist eine Variante des Modulmusters. Die Hauptunterschiede sind, dass alle Mitglieder (privat und öffentlich) innerhalb des Abschlusses definiert werden, der Rückgabewert ein Objektliteral ist, das keine Funktionsdefinitionen enthält, und alle Verweise auf Elementdaten über direkte Referenzen statt über das zurückgegebene Objekt erfolgen.
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 */);
Das Mustermuster wird enthüllt
Diese Variation des enthüllenden Musters wird verwendet, um den Konstruktor von den Methoden zu trennen. Dieses Muster erlaubt es uns, die Javascript-Sprache wie eine objektorientierte Sprache zu verwenden:
//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}
}();
Dieser Code sollte sich in einer separaten Datei mit der Erweiterung .js befinden, damit auf jeder Seite darauf verwiesen werden kann. Es kann wie folgt verwendet werden:
var menuActive = new NavigationNs.active('ul.sidebar-menu li', 5);
menuActive.setCurrent();
Prototypmuster
Das Prototypmuster konzentriert sich darauf, ein Objekt zu erstellen, das durch prototypische Vererbung als Blaupause für andere Objekte verwendet werden kann. Dieses Muster ist in JavaScript von Natur aus einfach zu verarbeiten, da native Unterstützung für prototypische Vererbung in JS zur Verfügung steht, sodass wir weder Zeit noch Mühe benötigen, um diese Topologie nachzuahmen.
Erstellen von Methoden für den Prototyp
function Welcome(name) {
this.name = name;
}
Welcome.prototype.sayHello = function() {
return 'Hello, ' + this.name + '!';
}
var welcome = new Welcome('John');
welcome.sayHello();
// => Hello, John!
Prototypische Vererbung
Das Vererben von einem übergeordneten Objekt ist mit dem folgenden Muster relativ einfach
ChildObject.prototype = Object.create(ParentObject.prototype);
ChildObject.prototype.constructor = ChildObject;
Wobei ParentObject
das Objekt ist, von dem Sie die prototypisierten Funktionen erben möchten, und ChildObject
das neue Objekt, für das Sie sie ChildObject
möchten.
Wenn das übergeordnete Objekt Werte enthält, die in seinem Konstruktor initialisiert werden, müssen Sie den übergeordneten Konstruktor beim Initialisieren des untergeordneten Objekts aufrufen.
Verwenden Sie dazu das folgende Muster im ChildObject
Konstruktor.
function ChildObject(value) {
ParentObject.call(this, value);
}
Ein vollständiges Beispiel, in dem das Obige implementiert ist
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!
Werksfunktionen
Eine Factory-Funktion ist einfach eine Funktion, die ein Objekt zurückgibt.
Factory-Funktionen erfordern nicht die Verwendung des new
Schlüsselworts, können aber dennoch zum Initialisieren eines Objekts wie eines Konstruktors verwendet werden.
Werksfunktionen werden häufig als API-Wrapper verwendet, wie z. B. bei jQuery und moment.js , sodass Benutzer keine new
.
Das Folgende ist die einfachste Form der Werksfunktion. Argumente nehmen und verwenden, um ein neues Objekt mit dem Objektliteral zu erstellen:
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 ist einfach, private Eigenschaften und Methoden in einer Fabrik zu definieren, indem Sie sie außerhalb des zurückgegebenen Objekts einschließen. Dadurch bleiben Ihre Implementierungsdetails gekapselt, sodass Sie die öffentliche Schnittstelle nur für Ihr Objekt verfügbar machen können.
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
Die letzte Zeile gibt einen Fehler aus, da die Funktion formalName
innerhalb der cowFactory
Funktion geschlossen ist. Dies ist eine Schließung .
In Fabriken können funktionale Programmierpraktiken auch in JavaScript angewendet werden, da es sich um Funktionen handelt.
Fabrik mit Komposition
"Komposition über Vererbung vorziehen" ist ein wichtiges und beliebtes Programmierprinzip, das verwendet wird, um Objekten Verhalten zuzuweisen, anstatt viele oft nicht benötigte Verhaltensweisen zu erben.
Verhaltensfabriken
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');
}
};
};
Objektfabriken
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)
);
};
Verwendungszweck
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
Abstraktes Fabrikmuster
Das abstrakte Fabrikmuster ist ein kreatives Entwurfsmuster, mit dem bestimmte Instanzen oder Klassen definiert werden können, ohne das genaue Objekt angeben zu müssen, das erstellt wird.
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 )