Ricerca…


introduzione

Gli schemi di progettazione sono un buon modo per mantenere il codice leggibile e ASCIUTTO. DRY sta per non ripetersi . Di seguito è possibile trovare ulteriori esempi sui modelli di progettazione più importanti.

Osservazioni

Nell'ingegneria del software, un modello di progettazione software è una soluzione generale riutilizzabile per un problema che si verifica comunemente in un dato contesto nella progettazione del software.

Singleton Pattern

Il pattern Singleton è un modello di progettazione che limita l'istanziazione di una classe a un oggetto. Dopo che il primo oggetto è stato creato, restituirà il riferimento allo stesso quando richiesto per un oggetto.

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

Modulo e modelli di moduli rivelatori

Modello del modulo

Il modello di modulo è un modello di progettazione creativa e strutturale che fornisce un modo per incapsulare membri privati ​​durante la produzione di un'API pubblica. Questo si ottiene creando un IIFE che ci consente di definire variabili disponibili solo nel suo ambito (attraverso la chiusura ) mentre restituiamo un oggetto che contiene l'API pubblica.

Questo ci offre una soluzione pulita per nascondere la logica principale e solo per esporre un'interfaccia che desideriamo utilizzare da altre parti della nostra applicazione.

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

Rivelare il modello del modulo

Il pattern Revealing Module è una variante del pattern Module. Le differenze chiave sono che tutti i membri (privati ​​e pubblici) sono definiti all'interno della chiusura, il valore restituito è un oggetto letterale che non contiene definizioni di funzioni e tutti i riferimenti ai dati dei membri vengono eseguiti tramite riferimenti diretti anziché tramite l'oggetto restituito.

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

Rivelando il modello di prototipo

Questa variazione del modello rivelatore viene utilizzata per separare il costruttore dai metodi. Questo modello ci consente di utilizzare il linguaggio javascript come un linguaggio orientato agli oggetti:

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

Questo codice sopra deve essere in un file .js separato a cui fare riferimento in qualsiasi pagina necessaria. Può essere usato in questo modo:

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

Modello di prototipo

Il modello prototipo si concentra sulla creazione di un oggetto che può essere utilizzato come progetto per altri oggetti attraverso l'ereditarietà prototipale. Questo pattern è intrinsecamente facile da utilizzare in JavaScript a causa del supporto nativo per l'ereditarietà di prototipi in JS, il che significa che non è necessario dedicare tempo o fatica a imitare questa topologia.


Creare metodi sul prototipo

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

var welcome = new Welcome('John');

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

Eredità prototipale

Ereditare da un "oggetto genitore" è relativamente facile attraverso il seguente schema

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

Dove ParentObject è l'oggetto da cui si desidera ereditare le funzioni prototipate, e ChildObject è il nuovo oggetto su cui si desidera inserirle.

Se l'oggetto genitore ha valori inizializzati nel suo costruttore è necessario chiamare il costruttore dei genitori durante l'inizializzazione del figlio.

Lo fai usando il seguente modello nel costruttore ChildObject .

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

Un esempio completo in cui è implementato quanto sopra

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!

Funzioni di fabbrica

Una funzione di fabbrica è semplicemente una funzione che restituisce un oggetto.

Le funzioni di fabbrica non richiedono l'uso della new parola chiave, ma possono ancora essere utilizzate per inizializzare un oggetto, come un costruttore.

Spesso le funzioni di fabbrica vengono utilizzate come wrapper API, come nel caso di jQuery e moment.js , quindi gli utenti non hanno bisogno di usare new .

Quanto segue è la forma più semplice di funzione di fabbrica; prendere argomenti e usarli per creare un nuovo oggetto con l'oggetto letterale:

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"

È facile definire proprietà e metodi privati ​​in una fabbrica, includendoli al di fuori dell'oggetto restituito. Ciò mantiene incapsulati i dettagli della tua implementazione, quindi puoi solo esporre l'interfaccia pubblica al tuo oggetto.

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

L'ultima riga darà un errore perché la funzione formalName è chiusa all'interno della funzione cowFactory . Questa è una chiusura .

Le fabbriche sono anche un ottimo modo di applicare pratiche di programmazione funzionale in JavaScript, perché sono funzioni.

Fabbrica con composizione

"Preferisci la composizione sull'ereditarietà" è un principio di programmazione importante e popolare, utilizzato per assegnare comportamenti agli oggetti, al contrario di ereditare molti comportamenti spesso non necessari.

Fabbriche di comportamento

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

Fabbriche oggetto

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

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

Modello astratto di fabbrica

Abstract Factory Pattern è un pattern di progettazione creazionale che può essere utilizzato per definire istanze o classi specifiche senza dover specificare l'oggetto esatto che viene creato.

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow