JavaScript Design Patterns: Decorator

Today I’d like to show another JavaScript Design Pattern: the Decorator, which is a way to add features to objects without subclassing or adding extra attributes. This post continues the JavaScript Design Patterns series that I started several months ago. If you’re new to the JavaScript Design Patterns series that I’m running here, you can find a list of the previous and upcoming posts in the series at the bottom of the post.

Back on Course with Tutorial Posts

After the exciting launch of my new jQuery plugin it’s been difficult to bring myself back to normal blogging and back to this series. If you don’t know what I’m talking about, then you should hop on over to the plugin’s announcement post (when you’re done reading this, of course). However, regardless of how this month started out, I’ve decided to make a commitment to at least 2 “tutorial” posts per month. I put the word “tutorial” in quotes because I’m not sure they can all be generally considered tutorials, but I’m using the word to mean any post whose purpose is to teach, as opposed to announcements or news and the like.

On with the Decorator Pattern

Let’s return to purpose of this post: learning about the decorator pattern. Like I said, this pattern permits us to add features to an object without needing to subclass it. Instead we “decorate” (wrap) it with another object with the same interface that has the one feature we’re adding. To get a better idea of what I’m talking about, let’s first demonstrate how someone lacking knowledge of the decorator pattern would attempt this, especially if they’re coming from a background of classical inheritance.

// Superclass
var Car = function() {...};

// Subclasses with different features
var CarWithPowerLocks = function() {...};
var CarWithPowerWindows = function() {...};
var CarWithPowerLocksAndPowerWindows = function() {...};
var CarWithAC = function() {...};
var CarWithACAndPowerLocks = function() {...};
var CarWithACAndPowerWindows = function() {...};
var CarWithACAndPowerLocksAndPowerWindows = function() {...};
...

As you can see, every combination of features needs to be represented by a new “class”. This might be okay if you have only a couple features, but once you start growing the number of features, this becomes more and more of a nightmare. Of course, if you want to be a jerk, you can do this in an app and leave it for someone else to maintain, but I don’t know how long you’d go before being punched in the face if that programmer needs to add another feature (or 5 more!).

How the Decorator Pattern can Help

Thankfully the Decorator Pattern can make things considerably simpler for us and future maintainers of our code. First we’ll create the base object that will be a Car with no cool features. This also sets up the interface that the decorators will use.

var Car = function() {
    console.log('Assemble: build frame, add core parts');
}

// The decorators will also need to implement these functions
// to comply with Car's interface.
Car.prototype = {
    start: function() {
        console.log('The engine starts with roar!');
    },
    drive: function() {
        console.log('Away we go!');
    },
    getPrice: function() {
        return 11000.00;
    }
}

Now we’ll create the decorator “class” that each of the decorator will inherit from. You’ll notice that each of the functions simply pass the call on to the Car that they’re wrapping. In this case the only functions that will be overridden are assemble and getPrice.

// You need to pass in the Car (or CarDecorator) in order to
// be able to add features to it.
var CarDecorator = function(car) {
    this.car = car;
}

// CarDecorator is implementing the same interface
CarDecorator.prototype = {
    start: function() {
        this.car.start();
    },
    drive: function() {
        this.car.drive();
    },
    getPrice: function() {
        return this.car.getPrice();
    }
}

Next we create a decorator object for each feature and override the parent's functions whenever we want to add more or different functionality there.

var PowerLocksDecorator = function(car) {
    // JavaScript's way of calling a parent class' constructor
    CarDecorator.call(this, car);
    console.log('Assemble: add power locks');
}
PowerLocksDecorator.prototype = new CarDecorator();
PowerLocksDecorator.prototype.drive = function() {
    // You can either do this
    this.car.drive();
    // or you can call the parent's drive function:
    // CarDecorator.prototype.drive.call(this);
    console.log('The doors automatically lock');
}

var PowerWindowsDecorator = function(car) {
    CarDecorator.call(this, car);
    console.log('Assemble: add power windows');
}
PowerWindowsDecorator.prototype = new CarDecorator();

var ACDecorator = function(car) {
    CarDecorator.call(this, car);
    console.log('Assemble: add A/C unit');
}
ACDecorator.prototype = new CarDecorator();
ACDecorator.prototype.start = function() {
    this.car.start();
    console.log('The cool air starts blowing.');
}

Notice that we always call the same function on the wrapped object as well. This is somewhat similar to the way a composite works, though the similarities between the two patterns pretty much end there. In this example, we always call the wrapped object’s function first before adding in the new information from the decorator (if any exists for that function). This creates the desired effect of having the core functions executing first, but other applications might require different order, or possibly might not even call the wrapped object’s function if the intention is to completely change the functionality rather than adding on to it.

Structure of the Decorator Pattern

Seeing our JavaScript in Action

So how do we use the code that we just spent this entire time making? Well the actual code is below, but maybe I should do a little explaining first. Of course, you’re free to skip this and jump straight to the code if you think you’ve got it down.

First we create a Car object. Then, we create the decorator for the feature we want to add onto it and pass the Car into its constructor. The object returned from the decorator’s constructor is assigned back to the variable that previously held the Car object because since the decorators use the same interface, they too can be considered Cars. We keep adding more features until we’re satisfied and then we have our desired car that we can do whatever we want with.

var car = new Car();                    // log "Assemble: build frame, add core parts"

// give the car some power windows
car = new PowerWindowDecorator(car);    // log "Assemble: add power windows"

// now some power locks and A/C
car = new PowerLocksDecorator(car);     // log "Assemble: add power locks"
car = new ACDecorator(car);             // log "Assemble: add A/C unit"

// let's start this bad boy up and take a drive!
car.start(); // log 'The engine starts with roar!' and 'The cool air starts blowing.'
car.drive(); // log 'Away we go!' and 'The doors automatically lock'

Concluding this Fiasco

The Decorator proves to be a nice way of maintaining differentiating features for an object and definitely helps improve maintainability over the long haul. You may have noticed, though, that I didn’t include any code to make sure that we didn’t accidentally add the same feature more than once. Don’t worry, the next post will give us a clean answer without having to change any of the code we’ve already written. Adding checks into the decorators to accomplish would prove to be annoying.

If you’ve got something to say about the Decorator Pattern, this post, or even just JavaScript in general, make your voice heard in the comments section below. I’d love to hear it, even if you’re just letting me know I’m an idiot (just try to make it more constructive than “you’re an idiot”). We all have to grow somehow. Also, I’d greatly appreciate if you’d use the social sharing buttons below to spread the word about this post. Little guys like me don’t get big without some help. Happy Coding!

JavaScript Design Patterns series:

About the Author

Author: Joe Zim

Joe Zim

Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.


  • thinkt4nk

    good post, but have you considered implementing a more formal interface pattern to govern the interfaces?

    • http://www.joezimjs.com Joe Zimmerman

      I definitely have. The only trouble is that if I use a special framework for interfaces, I have to also educate everyone about that also. I try to keep the lesson focused on the main topic so everyone can learn that without getting distracted by interface checking.
      Another point is that although they are helpful for making sure you have the right interface, as long as you are writing all your own code, or your entire team at least understands the interfaces of each object, there shouldn’t be a need to check to make sure the interface is correct. Plus, checking the interface can add a little overhead and slow down your application, albeit not much.

      • thinkt4nk

        all good points

      • Giorgio Sironi

        I appreciate the porting of patterns definition into a language community which may nit have encountered them, and I did something similar for the PHP case.
        About interfaces, I consider them more a modeling tool than something for introducing type checks, which are problematic in a dynamic language.
        Anyway, is there a way to wire up Decorator.prototype to the Car object to get automatic delegation?

        • http://www.joezimjs.com Joe Zimmerman

          Yea, in a Dynamic coding environment, your best bet is to just test to see if the method you’re looking for is available at the moment you use it.

          I’m not sure what you mean by your question. The way decorators work is to wrap an object and pretend that it is essentially that object by mimicking the interface. I don’t know what you mean by automatic delegation.

  • Jaime Huesos

    I’ve just wanted to say that I am enjoying this serie about JS patterns a lot: I discover it through The Javascript Newsletter and I have just read all of them. I look forwad to reading the rest of them (and I also will take a look to your PubSub plugin for jQuery).

    I am sorry, but this comment is not very “consctructive” since I have nothing bad to say about it.

    Cheers

    • http://www.joezimjs.com Joe Zimmerman

      No problem. I’m always glad to hear that people enjoy the blog. It makes it feel like it’s worth the time and effort I put into it. If you have any issues with the plugin or just have comments/suggestions, please leave a comment on the project page.

      Thanks,
      Joe Zim

  • Anonymous

    So an issue I have is that while this works, it requires you manually add each decorator during your initialize step, I imagine passing in decorators as a configuration during the initialization might be a bit cleaner. 

    OR having a car have a default list of decorators (so you can have similar behavior to Ruby modules / python mixins). I’m not sure if that would work or not.

    • http://www.joezimjs.com Joe Zimmerman

      In my next post about Factories, you’ll see an elegant way to create decorated objects quite easily.

  • Johnny Oshika

    Great post.  Thank you.

    • http://www.joezimjs.com Joe Zimmerman

      You’re very welcome.

  • https://plus.google.com/115997427907495628677/ Jacob

    Great reading, thanks a lot!

  • http://wilmoore.com Wil Moore III

    I am wondering if there is any merit in comparing the decorator pattern in JS to mixins. It is my opinion that the decorator pattern is mostly useful as an alternative in a language that doesn’t support mixins/traits. Am I missing something obvious with this way of thinking?

    • http://www.joezimjs.com Joe Zimmerman

      Decorators and Mixins are two very different beasts. A Decorator allows you to ADD functionality to a function that already exists, while Mixins will either create a new function or override it if the function with that name already exists. Granted some Decorators CAN just override functions, but generally the purpose is to add new “features”.

  • Damon Jasperson

    This is an excellent series since, in my experience, great engineers know how and when to use the GoF patterns.

    There are only minor points that I feel could be expanded upon:
    1. Present the UML. I’ve found that a minority of engineers can make the jump from UML to code and vice verse. Every great engineer I’ve ever worked with not only knew UML, but they also had a practical understanding of how the model translated to code.

    2. Perhaps a discussion of the runtime effects of the pattern would be insightful. For example, a Car can literally have hundreds of “features”. The impact of adding all features to a Car devolves into a linked list type of object graph that could potentially be expensive to traverse. Might there be other ways of “realizing” the Decorator, while reducing the linear behavior of instantiating a really nice Car with all “features?”

    Thanks again for this informative and well needed series!!