Decorator Design Pattern

Decorator Pattern

  • structural design pattern
  • aims to promote code re-use
  • alternative to sub-classing

add (decorate) properties/methods to a base object

var Hobbit = function(){
        //...
};
 
var  HobbitWithRing =  function(){},
     HobbitWithSword = function(){},
     HobbitWithRingAndSword = function(){},
     HobbitWithShoes = function(){},
     HobbitWithShoesAndRing = function(){},
     HobbitWithShoesAndRingAndSword = function(){},
     HobbitWithShoesAndSword = function(){};

From this ---^

var Hobbit = function(){
        //...
};

Hobbit.prototype.equipment = function() {
 return [];
};

// Decorator A
function Ring(hobbit) {
     var currentEquipment = hobbit.equipment();
     hobbit.equipment = function() {
         return currentEquipment.concat(['ring']);
     };

     return hobbit;
}

// Decorator B
function Sword(hobbit) {
    var currentEquipment = hobbit.equipment();
    hobbit.equipment = function() {
        return currentEquipment.concat(['sword']);
    };

    return hobbit;
}

// Here's one way of using it
var hobbit = new Sword(new Ring(new Hobbit ()));
console.log('hobbit.equipment', hobbit.equipment());

// Here's another
var hobbit2 = new Hobbit();
hobbit2 = new Ring(hobbit2);
hobbit2 = new Sword(hobbit2);
console.log('hobbit2.equipment', hobbit2.equipment());

To this --->

Pros & Cons

  • avoids need to rely on a large number of subclasses
  • objects can be wrapped/"decorated" with new behavior
  • base object won't be modified
  • con: can complicate the process of instantiating the component (have to wrap it in a number of decorators in addition to instantiating the component)

Decorator Demo

// Class to be decorated
function Coffee() {
}
Coffee.prototype.cost = function() {
 return 1;
};

// Decorator A
function Milk(coffee) {
 var currentCost = coffee.cost();
 coffee.cost = function() {
 return currentCost + 0.5;
 };

 return coffee;
}

// Decorator B
function Whip(coffee) {
 var currentCost = coffee.cost();
 coffee.cost = function() {
 return currentCost + 0.7;
 };

 return coffee;
}

// Decorator C
function Sprinkles(coffee) {
 var currentCost = coffee.cost();
 coffee.cost = function() {
 return currentCost + 0.2;
 };

 return coffee;
}

// Here's one way of using it
var coffee = new Milk(new Whip(new Sprinkles(new Coffee())));
alert( coffee.cost() );

// Here's another
var coffee = new Coffee();
coffee = new Sprinkles(coffee);
coffee = new Whip(coffee);
coffee = new Milk(coffee);
alert(coffee.cost());

Decorator Pattern

By Jacqueline Wijaya