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

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

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 )


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow