Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a good decorator pattern for javascript?

I need some simple objects that could become more complex later, with many different properties, so i thought to decorator pattern. I made this looking at Crockford's power constructor and object augmentation:

//add property to object
Object.prototype.addProperty = function(name, func){
    for(propertyName in this){
        if(propertyName == name){
            throw new Error(propertyName + " is already defined");
        }
    }
    this[name] = func;
};

//constructor of base object
var BasicConstructor = function(param){

    var _privateVar = param;
    return{
        getPrivateVar: function(){
            return _privateVar;
        }
    };
};

//a simple decorator, adds one private attribute and one privileged method 
var simpleDecorator = function(obj, param){

    var _privateVar = param;

    var privilegedMethod1 = function(){
        return "privateVar of decorator is: " + _privateVar;
    };

    obj.addProperty("privilegedMethod1", privilegedMethod1);

    return obj;
}

//a more complex decorator, adds public and private properties
var complexDecorator = function(obj, param1, param2){

    //private properties
    var _privateVar = param1;
    var _privateMethod = function(x){
        for(var i=0; i<x; i++){
            _privateVar += x;
        }
        return _privateVar;
    };

    //public properties
    var publicVar = "I'm public";
    obj.addProperty("publicVar", publicVar);

    var privilegedMethod2 = function(){
        return _privateMethod(param2); 
    };
    obj.addProperty("privilegedMethod2", privilegedMethod2);

    var publicMethod = function(){
        var temp = this.privilegedMethod2();
        return "do something: " + temp + " - publicVar is: " + this.publicVar;
    };
    obj.addProperty("publicMethod", publicMethod);

    return obj;
}

//new basic object
var myObj = new BasicConstructor("obj1");

//the basic object will be decorated
var myObj = simpleDecorator(obj, "aParam");

//the basic object will be decorated with other properties
var myObj = complexDecorator(obj, 2, 3);

Is this a good way to have Decorator Pattern in javascript? Are there other better ways to do this?

like image 359
Manuel Bitto Avatar asked May 10 '10 15:05

Manuel Bitto


People also ask

Do design patterns apply to JavaScript?

You may not know it, but you've used a JavaScript design pattern. Design patterns are reusable solutions to commonly occurring problems in software design. During any language's lifespan, many such reusable solutions are made and tested by a large number of developers from that language's community.

What is decorator pattern in JavaScript?

Decorators are the design pattern that allows behavior to be added to an individual object, either statically or dynamically without affecting the behavior of other objects from the same class. They are used to enhance the functionality of the function without modifying the underlying function.

What is the decorator pattern good for?

The Decorator Pattern allows class behavior to the decorated dynamically. It's a structural design pattern as it's used to form large object structures across many disparate objects. The concept of decorator is that it adds additional attributes to an object dynamically.


1 Answers

There are various implementations of the Decorator pattern in Javascript on Wikipedia and other sites - (1), (2), (3). The pattern is defined as:

the decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing object dynamically.

Object extension is already build into the language itself. Objects can be easily extended, and properties can be added anytime. So why should you have to jump through hoops to achieve this? Shouldn't something like this suffice:

var person = { name: "Jack Bauer" };

// Decorated the object with ability to say a given phrase
person.say = function(phrase) {
    alert(phrase);
}

// Using the decorated functionality
person.say("Damn it!");

If you want a method to apply to all objects that were created using this function, then add that method/properties to the function's prototype.

Update: If you have clearly defined pieces of functionality which can be mixed and matched as needed into certain types of objects, then the MooTools approach of extending and mixing in behavior into objects is nicely done. To give an example, consider a UI component that can be resized, dragged around with a handle, and deleted by clicking a tick mark at the top-right corner. You may not want to create each component with these behaviors but define all these behaviors separately each into their own object. And later mix in these behaviors into each type of component as needed.

var Resizable = {
   ...
};

var Draggable = {
   ...
};

var Deletable = {
   ...
};

var someLabel = new Label("Hello World");

// one way to do it
someLabel.implement([Resizable, Draggable, Deletable]);

// another way to do it
someLabel.implement(Resizable);
someLabel.implement(Draggable);
someLabel.implement(Deletable);

It looks better and more intuitive (to me) than doing something like

var awesomeLabel = new Resizable(new Draggable(new Deletable(someLabel)));

because we are still dealing with a label, and not some resizable, or some draggable, or some deletable object. Another small point, but still worth mentioning is that the parentheses start getting unmanageable after 3 or 4 decorators, especially without good IDE support.

like image 88
Anurag Avatar answered Oct 31 '22 01:10

Anurag