Przykłady praktycznych wzorców projektowych zorientowanych obiektowo w javascript

81

Jakich wzorców projektowych zorientowanych obiektowo używasz w javascript swojej aplikacji i dlaczego?

Zapraszam do wysłania kodu pocztowego, nawet jeśli nie ma do niego dołączonego formalnego wzoru projektowego.

Napisałem wiele skryptów JavaScript, ale nie zastosowałem zbyt wielu wzorców obiektowych do tego, co robię, i jestem pewien, że wiele mi brakuje.

ming yeow
źródło
Prawdopodobnie nie widziałeś klasycznego OOP w takim sensie, w jakim mógłbyś pomyśleć. Jednak prawdopodobnie używałeś funkcji z prototypowym OOP i nigdy tak naprawdę nie zdawałeś sobie z tego sprawy.
dave
Właściwie (czasami) zdaję sobie sprawę, kiedy używam OOP - chcę zacząć używać OOP znacznie bardziej świadomie, właśnie dlatego, że chcę być o wiele bardziej przemyślany
ming yeow
Głosuję za zamknięciem tego pytania jako niezwiązanego z tematem, ponieważ jest to po prostu prośba o listę rzeczy, które inni ludzie robią w swoim kodzie.
Almo,

Odpowiedzi:

54

Poniżej przedstawiono trzy popularne wzorce JavaScript. Są one łatwe do wdrożenia z powodu zamknięć :

Możesz również sprawdzić:

Poniżej znajduje się wykład Google I / O z 2008 r. Wygłoszony przez Diaza, w którym omawia niektóre tematy ze swojej książki:

Daniel Vassallo
źródło
miły! curry wygląda na mądrzejszy sposób na uogólnienie, które próbowałem zrobić. już korzystam z prostych form modułu i zapamiętywania - ale muszę przestudiować te przykłady, aby pokazać, jak obecnie to robię. Których używasz najczęściej?
ming yeow
@ming: Prawdopodobnie jest to wzorzec modułu. Bardzo łatwy do zaimplementowania i zrozumienia, posiada kilka fajnych funkcji, w tym przestrzeń nazw i prywatne zmienne / metody.
Daniel Vassallo,
26

Dziedzictwo

Używam notacji do dziedziczenia opartej na ExtJS 3 , który, moim zdaniem , działa bardzo podobnie do emulacji klasycznego dziedziczenia w Javie. Zasadniczo działa w następujący sposób:

// Create an 'Animal' class by extending
// the 'Object' class with our magic method
var Animal = Object.extend(Object, {
    move : function() {alert('moving...');}
});

// Create a 'Dog' class that extends 'Animal'
var Dog = Object.extend(Animal, {
    bark : function() {alert('woof');}
});

// Instantiate Lassie
var lassie = new Dog();

// She can move and bark!
lassie.move();
lassie.bark();

Przestrzenie nazw

Zgadzam się również z Erikiem Miraglia co do trzymania się przestrzeni nazw, więc powyższy kod powinien być uruchamiany w swoim własnym kontekście poza obiektem okna, jest to krytyczne, jeśli zamierzasz działać jako jeden z wielu współbieżnych frameworków / bibliotek wykonujących się w oknie przeglądarki.

Oznacza to, że jedyną drogą do obiektu okna jest własna przestrzeń nazw / obiekt modułu:

// Create a namespace / module for your project
window.MyModule = {};

// Commence scope to prevent littering 
// the window object with unwanted variables
(function() {

    var Animal = window.MyModule.Animal = Object.extend(Object, {
         move: function() {alert('moving...');}
    });

    // .. more code

})();

Interfejsy

Możesz także skorzystać z większej liczby zaawansowanych konstrukcji OOP, takich jak interfejsy, aby ulepszyć projekt aplikacji. Moje podejście do tego polega na wzmocnieniu znaku Function.prototypew celu uzyskania notacji w następujący sposób:

var Dog = Object.extend(Animal, {
     bark: function() {
         alert('woof');
     }
     // more methods ..
}).implement(Mammal, Carnivore);

OO Patterns

Jeśli chodzi o `` wzorce '' w sensie Java, znalazłem zastosowanie tylko dla wzorca Singleton (świetnego do buforowania) i wzorca Observer do funkcji sterowanych zdarzeniami, takich jak przypisywanie niektórych akcji, gdy użytkownik kliknie przycisk.

Przykład wykorzystania wzorca obserwatora wyglądałby następująco:

// Instantiate object
var lassie = new Animal('Lassie');

// Register listener
lassie.on('eat', function(food) {
   this.food += food;
});

// Feed lassie by triggering listener
$('#feeding-button').click(function() {
    var food = prompt('How many food units should we give lassie?');
    lassie.trigger('eat', [food]);
    alert('Lassie has already eaten ' + lassie.food + ' units');
});

A to tylko kilka sztuczek w mojej torbie z OO JS, mam nadzieję, że ci się przydadzą.

Jeśli zamierzasz pójść tą drogą, polecam przeczytać Douglas Crockfords Javascript: The Good Parts . To świetna książka do tego wszystkiego.

Steven de Salas
źródło
20

Jestem fanem Module Pattern . Jest to sposób na implementację rozszerzalnych, niezależnych (w większości przypadków) frameworków.

Przykład:

Ramy,, Qsą zdefiniowane w następujący sposób:

var Q = {};

Aby dodać funkcję:

Q.test = function(){};

Te dwa wiersze kodu są używane razem do tworzenia modułów . Idea stojąca za modułami polega na tym, że w tym przypadku wszystkie one rozszerzają podstawową strukturę, Qale nie są od siebie zależne (jeśli zostały prawidłowo zaprojektowane) i mogą być dołączane w dowolnej kolejności.

W module najpierw tworzysz obiekt frameworka, jeśli nie istnieje (co jest przykładem wzorca Singleton ):

if (!Q)
    var Q = {};

Q.myFunction = function(){};

W ten sposób możesz mieć wiele modułów (takich jak powyższy) w oddzielnych plikach i dołączać je w dowolnej kolejności. Każdy z nich utworzy obiekt szkieletu, a następnie go rozszerzy. Nie ma potrzeby ręcznego sprawdzania, czy ramy istnieją. Następnie, aby sprawdzić, czy moduł / funkcja istnieje w kodzie niestandardowym:

if (Q.myFunction)
    Q.myFunction();
else
    // Use a different approach/method
Chris Laplante
źródło
1
Wygląda to na niezwykle przydatne. jak używasz tego w swoim kodzie? dzięki za udostępnienie!
ming yeow
Użyłem go w ostatnim projekcie, w którym miałem oddzielne pliki JavaScript dla typowych funkcji, interfejsu użytkownika i dwóch innych wyspecjalizowanych mechanizmów. Wszystkie pliki dodały funkcje do tego samego frameworka (zdefiniowanego za pomocą metody, którą pokazałem powyżej) i nazywały funkcje, tak jak zrobiłem powyżej.
Chris Laplante,
Jednym z głównych zastosowań tego typu techniki jest unikanie zanieczyszczenia globalnej przestrzeni nazw. Co bardziej zanieczyszcza? Pojedyncza Qzmienna frameworka, czy dziesiątki funkcji i zmiennych?
Chris Laplante,
6

Wzorzec singleton jest często bardzo pomocny w przypadku „hermetyzacji” i organizacji. Możesz nawet zmienić dostępność.

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

najczystszy sposób implementacji singletona w javascript

Gordon Gustafson
źródło
super - to jest ten, którego używam cały czas! Ale to tylko o zakresie mojego OO javascript. ;)
ming yeow
4

Bardzo podoba mi się wzorzec łączenia metod w jquery , umożliwiający wywołanie kilku metod na jednym obiekcie. Ułatwia to wykonanie kilku operacji w jednej linii kodu.

Przykład:

$('#nav').click(function() {
   $(this).css('color','#f00').fadeOut();
});
GSto
źródło
dobrze - zgodził się! Czy już wcześniej opracowałeś własne, niestandardowe metody, które działają w ten sposób?
ming yeow
3

Bardzo podoba mi się wzorzec Decorator z wtyczkami jQuery. Zamiast modyfikować wtyczki, aby spełnić Twoje potrzeby, napisz niestandardową wtyczkę, która po prostu przekazuje żądania i dodaje dodatkowe parametry i funkcje.

Na przykład, jeśli musisz przez cały czas przekazywać zestaw domyślnych argumentów i potrzebujesz nieco innego zachowania, które wiąże się z logiką biznesową, napisz wtyczkę, która zrobi wszystko prei postzadziała, aby spełnić Twoje potrzeby i przekaże domyślne argumenty jeśli te konkretne argumenty nie są określone.

Główną zaletą tego jest to, że możesz aktualizować swoje biblioteki i nie martwić się o przenoszenie zmian w bibliotekach. Twój kod może się zepsuć, ale jest przynajmniej szansa, że ​​tak się nie stanie.

Stefan Kendall
źródło
To brzmi jak świetny pomysł. Czy masz rzeczywisty przykład w kodzie, aby wykonać faktyczne rozszerzenie? Nawet prosty przykład bardzo wszystkim pomoże.
ming yeow
3

Jednym z przydatnych wzorców w świecie javascript jest łańcuchowy wzorzec, który jest spopularyzowany przez LINQ w pierwszej kolejności, a także jest używany w jQuery.

ten wzorzec umożliwia nam wywoływanie różnych metod klasy w sposób łańcuchowy.

główna struktura tego wzoru byłaby następująca

var Calaculator = function (init) {
    var result = 0;
    this.add = function (x) { result += (init + x); return this; };
    this.sub = function (x) { result += (init - x); return this; };
    this.mul = function (x) { result += (init * x); return this; };
    this.div = function (x) { result += (init / x); return this; };

    this.equals = function (callback) {
        callback(result);
    }

    return this;
};


new Calaculator(0)
    .add(10)
    .mul(2)
    .sub(5)
    .div(3)
    .equals(function (result) {
        console.log(result);
    });

Kluczową ideą tego wzorca jest thissłowo kluczowe, które umożliwia dostęp do innego publicznego członka funkcji Kalkulatora.

Matrix Buster
źródło