2

I am trying to get a decorator pattern to work follwing

http://www.joezimjs.com/javascript/javascript-design-patterns-decorator/

I might have missed some point but the pattern does not work as i expect.

If i add two decorators and add them to a class the functions are not passed through as i thought. Only the last decorator's functions can be called or the basic Decorator is called. The chaining is broken. How do i fix this?

I added a fiddle:

http://jsfiddle.net/hbyLW/25/

UPDATE: Corrected Version

http://jsfiddle.net/hbyLW/29/

And the source code:

// A basic device class
var device = function(options) {
    this.brightness = options.brightness;
    this.Id = options.Id;
    this.motion = options.motion;
};

// Adding some functions to the class
device.prototype = {

    getID: function() {
        console.log("This ID:" + this.device.Id);
        return this.Id;
    },
    getBrightness: function() {
        console.log("This Brightness: " + this.brightness);
        return this.brightness;
    },
    getMotion: function() {
        console.log("This Motion: " + this.motion);
        return this.motion;
    }
};

// A device Decorator 
var deviceDecorator = function(device) {
    this.device = device;
};

// Adding pass through functions to the Decorator
deviceDecorator.prototype = {
    getId: function() {
        console.log("Old Id");
        return this.device.getId;
    },
    getBrightness: function() {
        console.log("Old Brightness");
        return this.device.getBrightness;
    },
    getMotion: function() {
        console.log("Old Motion");
        return this.device.getMotion;
    }
};

// A Decorator that adds some functionality to the getBrightness function
var brightnessDecorator = function(device) {
    deviceDecorator.call(this, device);
};

brightnessDecorator.prototype = new deviceDecorator();

brightnessDecorator.prototype.getBrightness = function() {
    this.device.getBrightness();
    console.log("Changed Brightness");
};

var motionDecorator = function(device) {
    deviceDecorator.call(this, device);
};

// A Decorator that adds some functionality to the getMotion function
motionDecorator.prototype = new deviceDecorator();

motionDecorator.prototype.getMotion = function() {
    this.device.getMotion();
    console.log("changed Motion");
};

// Some options for a device
var options = {
    Id: "Identifier",
    brightness: true,
    motion: false
};

// Create a new device
var Lamp = new device(options);
// Add the decorators to the device
Lamp = new brightnessDecorator(Lamp);
Lamp = new motionDecorator(Lamp);

// Executing the functions
Lamp.getId();
Lamp.getMotion();
Lamp.getBrightness();
console.log(Lamp);?
2
  • Within the device prototype functions, it should be this.brightness and not this.device.brightness same goes for the others. Commented Dec 6, 2012 at 13:54
  • Just one thing: You could use Object.create(deviceDecorator.prototype) instead of new deviceDecodrator. This only does the chaining and avoids actually running the constructor. (old browsers might not have this function available though. In that case, its a very easy shim to make and it probably should be available in many llibraries too) Commented Dec 6, 2012 at 14:03

1 Answer 1

3

Your first decorator returns device.getID (the function itself) rather than calling it and returning the value it returns.

deviceDecorator.prototype = {
  getID: function() {
    console.log("Old Id");
    return this.device.getID(); // <= call function instead of returning it
  },
  ...
}

Also, make sure your capitalization is consistent.

Sign up to request clarification or add additional context in comments.

2 Comments

thank you for your answer. I have a second little question: I have a setter for one of the device's attributes, say brightness. Can i access the original device somehow? Because if there is no passthrough already, defining the functionality later is not possible if i want to act on the original device
I figured out another way to do the decorator pattern. I think this is much better : jsfiddle.net/Hh2vt/3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.