Decorator

The Decorator module gives you a means of implementing the decorator pattern with minimal boilerplate and code duplication. When creating a decorator class, you only need to define methods that differ in some way from the methods in the decorated object (the component). This means you don’t have to write lots of forwarding methods by hand, which saves you time, filesize, and reduces code duplication.

// In the browser
JS.require('JS.Decorator', function(Decorator) { ... });

// In CommonJS
var Decorator = require('jsclass/src/decorator').Decorator;

Let’s take a quick example:

// Basic Bike class. Bikes cost $10 per gear.

var Bike = new Class({
    initialize: function(model, gears) {
        this.model = model;
        this.gears = gears;
    },
    getModel: function() {
        return this.model;
    },
    getPrice: function() {
        return 10 * this.gears;
    },
    applyBrakes: function(force) {
        // slow the bike down...
    }
});

// Disk brake decorator. Disk brakes add to the price, and make the bike's
// brakes more powerful.

var DiskBrakeDecorator = new Decorator(Bike, {
    getPrice: function() {
        return this.component.getPrice() + 50;
    },
    applyBrakes: function(force) {
        this.component.applyBrakes(8 * force);
    }
});

DiskBrakeDecorator gets versions of all Bike’s instance methods that forward the method call onto the component and return the result. e.g., DiskBrakeDecorator’s getModel() method looks like:

getModel: function() {
    return this.component.getModel();
};

Any methods you don’t redefine in the decorator class will look similar to this. Let’s try our new classes out:

var bike = new Bike('Specialized Rock Hopper', 21);
bike.getPrice()   // -> 210

bike = new DiskBrakeDecorator(bike);
bike.getPrice()   // -> 260
bike.getModel()   // -> "Specialized Rock Hopper"

Within your decorator methods, use this.component to refer to the decorated object. If a decorator defines new methods, they will be passed through by any other decorators you wrap an object with.

var HornDecorator = new Decorator(Bike, {
    beepHorn: function(noise) {
        return noise.toUpperCase();
    }
});

var bike = new Bike('Specialized Rock Hopper', 21);

// Let's wrap a HornDecorator with a DiskBrakeDecorator
bike = new HornDecorator(bike);
bike = new DiskBrakeDecorator(bike);

bike.beepHorn('beep!')    // -> "BEEP!"