JavaScript Coding Patterns: Das „Module Pattern“

Avatar von Norbert Schmidt

In diesem dritten Teil der Reihe JavaScript Coding Patterns wird das sogenannte Module Pattern vorgestellt. Hierbei handelt es sich um eine Kombination aus einer Closure, einer Immediate Funktion und einem Objekt Literal, drei Patterns die bereits im ersten Teil und im zweiten Teil dieser Reihe erläutert wurden.

Module in JavaScript

JavaScript bietet von sich aus keine Import- und Export-Deklarationen an, mit denen Code modular strukturiert und geladen werden könnte. Es existieren allerdings Vorschläge, dies für ECMAScript 6 Harmony zu implementieren. Außerdem gibt es bereits seit einiger Zeit eine Spezifikation von CommonJS für Module und natürlich den bekannten und viel genutzten File- und Module-Loader RequireJS.

Das Module Pattern stellt aber eine wesentlich ältere und weitverbreitete Art und Weise dar, mit der JavaScript-Code in voneinander unabhängige Module aufgeteilt werden kann.

Prinzip

Das folgende Beispiel zeigt das Module Pattern in seiner einfachsten Form:

var application = (function () {
    // (1) Private Attribute und Methoden definieren:
    var name = 'Awesome Application I';

    var version = 'v0.1.0';

    // (2) Öffentliche API zur Verfügung stellen:
    return {
        launch: function () {
            return name + ' was launched successfully!';
        }
    };
}());

application.launch(); // 'Awesome Application was launched successfully!'

Der globalen Variable application wurde hier eine Immediate Function zugewiesen. Im Rahmen dieser Funktion werden zum einen private Attribute und Methoden deklariert. Privat sind sie deshalb, da sie nur innerhalb des Scopes der Funktion sichtbar sind. Eine Kollision mit anderen Programmteilen kann so ausgeschlossen werden. Zum anderen wird ein Objekt mit Methoden zurückgegeben. Das ist die öffentliche API, auf die außerhalb des Moduls zugegriffen werden kann.

Herkunft des Patterns

Ursprünglich wurde das Module Pattern vor vielen Jahren unter anderem von Richard Cronford in einer Google-Group-Diskussion über Closures ins Spiel gebracht. Douglas Crockford machte dann das Pattern während seiner Arbeit bei Yahoo bekannt. Im Grunde genommen findet sich das Module Pattern in vielen JavaScript Libraries und Frameworks wieder, von YUI, über Dojo, bis hin zu jQuery und AngularJS.

Variationen

Es gibt einige Varianten des Module Patterns von denen ich im Folgenden drei darstellen möchte.

1. Global Import
In der ersten Variante geht es um den Import von globalen Variablen in das Modul. Dies geschieht über den Function Call Operator, das Paar runder Klammern am Ende der Funktionsdefinition. Im nächsten Beispiel wird auf diese Weise das globale Window-Objekt in das Modul application hineingereicht und unter dem lokalen Alias global verwendet:

var application = (function (global) {
    var name = 'Awesome Application II';

    var version = 'v0.2.0';

    return {
        getVersion: function () {
            global.alert('Version ' + version);
        }
    };
}(window));

2. Module Export
In ein Modul können nicht nur globale Variablen importiert werden. Das Module Pattern ist auch dazu geeignet, globale Variablen zu definieren und zurückzuliefern. Auch in so einem Fall werden als erstes private und öffentliche Eigenschaften definiert. Eines dieser privaten Eigenschaften ist im nächsten Beispiel das Objekt auth, welches zunächst um Methoden erweitert und dann als Ganzes zurückgegeben wird:

var authentication = (function () {
    var identity = null;
    var status = false;

    var setIdentity = function (user) {
        identity = user;
    };

    var auth = {};

    auth.login = function () {
        return status = true;
    };
    auth.logout = function () {
        return status = false;
    };

    return auth;
}());

3. Revealing Module Pattern
Die letzte Spielart des Module Patterns, die ich hier vorstelle, ist das sogenannte Revealing Module Pattern von Christian Heilmann. In dieser Variante werden einfach alle Attribute und Methoden im privaten Scope definiert. Das am Ende zurückgelieferte Objekt, die öffentliche API des Moduls, beinhaltet dann nur noch Zeiger auf diejenigen privaten Funktionen und Variablen, die öffentlich zur Verfügung stehen sollen:

basket = (function () {
    var basket = [];

    var countItem = function () {
        return basket.length;
    };

    var addItem = function (item) {
        basket.push(item);
        return countItem();
    };

    var calculateTotal = function () {
        var total = 0, i;
        for (i = 0; i < countItem(); i += 1) {
            total += basket[i].price;
        }
        return total;
    };

    return {
        add: addItem,
        calculate: calculateTotal
    };
}());

basket.add({name: 'Hose', price: 22.50})
basket.add({name: 'Jacke', price: 19.90})
basket.calculate()                          // 42.40

Fazit

Das Module Pattern ermöglicht es, eine sehr übersichtliche Code-Struktur zu schaffen, eine klare Unterscheidung zwischen privaten und öffentlichen Eigenschaften zu emulieren und letztlich den Code modular aufzubauen. Das spricht eindeutig dafür, das Module Pattern zu nutzen. Was gegen seine Verwendung spricht, oder zumindest seine Verwendung problematisch machen kann, ist eben die Tatsache, dass dieses Pattern den Code in quasi private und öffentliche Bereiche aufteilt. Dadurch wird das Debugging und auch das Unit-Testing für derart strukturierten Code wesentlich komplizierter.

Die Rolle die Prototypen als Basis von Objekt-Vererbung in JavaScript spielen, davon handelt der vierte Teil  der Reihe JavaScript Coding Patterns.

Weiter lesen und lernen!

Avatar von Norbert Schmidt

Kommentare

Eine Antwort zu „JavaScript Coding Patterns: Das „Module Pattern““

  1. JavaScript Coding Patterns: Das “Module Pattern” https://t.co/giuj0BCZgM via @mayflowerphp

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.