Szukaj…


Wprowadzenie

Wzorce projektowe są dobrym sposobem na zachowanie czytelności i DRY. DRY oznacza nie powtarzaj się . Poniżej można znaleźć więcej przykładów najważniejszych wzorów projektowych.

Uwagi

W inżynierii oprogramowania wzorzec projektowania oprogramowania jest ogólnym rozwiązaniem wielokrotnego użytku dla często występującego problemu w danym kontekście w projektowaniu oprogramowania.

Singleton Pattern

Wzorzec Singleton to wzorzec projektowy, który ogranicza tworzenie instancji klasy do jednego obiektu. Po utworzeniu pierwszego obiektu zwraca odwołanie do tego samego, ilekroć zostanie wywołany dla obiektu.

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

Stosowanie:

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

Moduły i ujawnianie wzorów modułów

Wzór modułu

Wzorzec modułu to kreacyjny i strukturalny wzorzec projektowy, który zapewnia sposób enkapsulacji prywatnych członków podczas tworzenia publicznego API. Odbywa się to poprzez utworzenie IIFE, który pozwala nam zdefiniować zmienne dostępne tylko w jego zakresie (poprzez zamknięcie ), zwracając obiekt zawierający publiczny interfejs API.

To daje nam czyste rozwiązanie do ukrywania głównej logiki i ujawniania interfejsu, którego chcielibyśmy używać z innych części naszej aplikacji.

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

Odkrywający wzór modułu

Wzór modułu ujawniania jest odmianą wzoru modułu. Kluczowe różnice polegają na tym, że wszystkie elementy (prywatne i publiczne) są zdefiniowane w zamknięciu, zwracana wartość jest literałem obiektu nie zawierającym definicji funkcji, a wszystkie odwołania do danych elementu są dokonywane przez bezpośrednie odwołania, a nie przez zwracany obiekt.

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

Odkrywając wzór prototypu

Ta odmiana ujawniającego się wzoru służy do oddzielenia konstruktora od metod. Ten wzorzec pozwala nam używać języka javascript jako języka zorientowanego obiektowo:

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

Powyższy kod powinien znajdować się w oddzielnym pliku .js, do którego można się odwoływać na każdej potrzebnej stronie. Można go użyć w następujący sposób:

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

Wzór prototypu

Wzorzec prototypowy skupia się na stworzeniu obiektu, który może być użyty jako plan dla innych obiektów poprzez dziedziczenie prototypowe. Ten wzorzec jest z natury łatwy w obsłudze w JavaScript ze względu na natywną obsługę dziedziczenia prototypów w JS, co oznacza, że nie musimy tracić czasu ani wysiłku naśladując tę topologię.


Tworzenie metod na prototypie

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

var welcome = new Welcome('John');

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

Dziedziczenie prototypowe

Dziedziczenie po „obiekcie nadrzędnym” jest stosunkowo łatwe dzięki poniższemu wzorowi

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

Gdzie ParentObject to obiekt, od którego chcesz odziedziczyć prototypowane funkcje, a ChildObject to nowy obiekt, na którym chcesz je umieścić.

Jeśli obiekt nadrzędny ma wartości, które inicjuje w swoim konstruktorze, musisz wywołać konstruktor nadrzędny podczas inicjowania dziecka.

Robisz to za pomocą następującego wzorca w konstruktorze ChildObject .

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

Kompletny przykład realizacji powyższego

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!

Funkcje fabryczne

Funkcja fabryczna to po prostu funkcja zwracająca obiekt.

Funkcje fabryczne nie wymagają użycia new słowa kluczowego, ale nadal mogą być używane do inicjowania obiektu, takiego jak konstruktor.

Często funkcje fabryczne są używane jako opakowania API, tak jak w przypadku jQuery i moment.js , więc użytkownicy nie muszą używać new .

Oto najprostsza forma funkcji fabrycznej; przyjmowanie argumentów i używanie ich do tworzenia nowego obiektu za pomocą literału obiektu:

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"

Łatwo jest zdefiniować prywatne właściwości i metody w fabryce, umieszczając je poza zwracanym obiektem. Dzięki temu szczegóły implementacji są hermetyzowane, dzięki czemu można udostępnić publiczny interfejs tylko dla obiektu.

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

Ostatni wiersz spowoduje błąd, ponieważ funkcja formalName jest zamknięta wewnątrz funkcji cowFactory . To jest zamknięcie .

Fabryki są także świetnym sposobem na stosowanie funkcjonalnych praktyk programowania w JavaScript, ponieważ są funkcjami.

Fabryka z kompozycją

„Preferuj kompozycję zamiast dziedziczenia” jest ważną i popularną zasadą programowania, stosowaną do przypisywania zachowań obiektom, w przeciwieństwie do dziedziczenia wielu często niepotrzebnych zachowań.

Fabryki zachowań

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

Fabryki obiektów

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

Stosowanie

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

Abstrakcyjny wzór fabryki

Abstrakcyjny wzorzec fabryczny to kreacyjny wzorzec projektowy, którego można użyć do zdefiniowania określonych instancji lub klas bez konieczności określania dokładnie tworzonego obiektu.

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow