Zoeken…


Invoering

Ontwerppatronen zijn een goede manier om uw code leesbaar en DROOG te houden. DRY staat voor herhaal jezelf niet . Hieronder vindt u meer voorbeelden over de belangrijkste ontwerppatronen.

Opmerkingen

In software engineering is een software-ontwerppatroon een algemene herbruikbare oplossing voor een veel voorkomend probleem binnen een gegeven context in software-ontwerp.

Singleton patroon

Het Singleton-patroon is een ontwerppatroon dat de instantiëring van een klasse tot één object beperkt. Nadat het eerste object is gemaakt, retourneert het de verwijzing naar hetzelfde telkens wanneer er om een object wordt gevraagd.

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

Gebruik:

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

Module en onthullende modulepatronen

Module patroon

Het modulepatroon is een creatief en structureel ontwerppatroon dat een manier biedt om privéleden in te kapselen en tegelijkertijd een openbare API te produceren. Dit wordt bereikt door een IIFE te maken waarmee we variabelen kunnen definiëren die alleen beschikbaar zijn binnen het bereik (door afsluiting ), terwijl een object wordt geretourneerd dat de openbare API bevat.

Dit biedt ons een schone oplossing om de hoofdlogica te verbergen en alleen een interface bloot te leggen die we in andere delen van onze applicatie willen gebruiken.

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 */);

Onthullend modulepatroon

Het Revealing Module-patroon is een variant in het Module-patroon. De belangrijkste verschillen zijn dat alle leden (privé en openbaar) binnen de afsluiting worden gedefinieerd, de retourwaarde een letterlijk object is dat geen functiedefinities bevat en alle verwijzingen naar lidgegevens worden gedaan via directe verwijzingen in plaats van via het geretourneerde object.

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 */);

Onthullend prototypepatroon

Deze variatie van het onthullende patroon wordt gebruikt om de constructor te scheiden van de methoden. Met dit patroon kunnen we de javascript-taal gebruiken als een georiënteerde taal:

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

Deze bovenstaande code moet in een gescheiden bestand .js zijn waarnaar moet worden verwezen op elke gewenste pagina. Het kan als volgt worden gebruikt:

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

Prototype patroon

Het prototypepatroon richt zich op het creëren van een object dat kan worden gebruikt als een blauwdruk voor andere objecten door middel van prototypische overerving. Dit patroon is inherent eenvoudig om mee te werken in JavaScript vanwege de native ondersteuning voor prototypische overerving in JS, wat betekent dat we geen tijd of moeite hoeven te besteden om deze topologie te imiteren.


Methoden maken op het prototype

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

var welcome = new Welcome('John');

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

Prototypale erfenis

Het overnemen van een 'bovenliggend object' is relatief eenvoudig via het volgende patroon

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

Waar ParentObject het object is waarvan u de prototypefuncties wilt erven, en ChildObject het nieuwe object is waarop u ze wilt plaatsen.

Als het bovenliggende object waarden heeft die het in de constructor initialiseert, moet u de ouderconstructor aanroepen wanneer het kind wordt geïnitialiseerd.

U doet dat met het volgende patroon in de constructor ChildObject .

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

Een compleet voorbeeld waarbij het bovenstaande is geïmplementeerd

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!

Fabrieksfuncties

Een fabrieksfunctie is gewoon een functie die een object retourneert.

Voor fabrieksfuncties is het gebruik van het new trefwoord niet nodig, maar het kan nog steeds worden gebruikt om een object te initialiseren, zoals een constructor.

Vaak worden fabrieksfuncties gebruikt als API-wrappers, zoals in het geval van jQuery en moment.js , zodat gebruikers geen new hoeven te gebruiken.

Het volgende is de eenvoudigste vorm van fabrieksfunctie; argumenten nemen en gebruiken om een nieuw object met het letterlijke object te maken:

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"

Het is gemakkelijk om privéeigenschappen en -methoden in een fabriek te definiëren door ze buiten het geretourneerde object op te nemen. Hierdoor blijven uw implementatiegegevens ingekapseld, zodat u de openbare interface alleen aan uw object kunt blootstellen.

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

De laatste regel geeft een fout omdat de functie formalName is gesloten in de cowFactory functie. Dit is een sluiting .

Fabrieken zijn ook een geweldige manier om functionele programmeermethoden in JavaScript toe te passen, omdat het functies zijn.

Fabriek met compositie

'Samenstelling verkiezen boven overerving' is een belangrijk en populair programmeerprincipe, dat wordt gebruikt om gedrag aan objecten toe te wijzen, in tegenstelling tot het erven van veel vaak onnodig gedrag.

Gedrag fabrieken

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

Object fabrieken

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

Gebruik

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

Abstract fabriekspatroon

Het abstracte fabriekspatroon is een creatief ontwerppatroon dat kan worden gebruikt om specifieke instanties of klassen te definiëren zonder het exacte object te specificeren dat wordt gemaakt.

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow