JMU
The Composite Pattern in ECMAScript/JavaScript
An Introduction with Examples


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Motivation
One Version

In UML:

images/composite.gif
An Example of the Composite Pattern

A Recipe System

images/composite_example_ECMAScript.gif
An Example of the Composite Pattern (cont.)

The Instruction Class Click here for a demonstration.

ecmascriptexamples/composite/Instruction.js
        /**
 * An encapsulation of an Instruction
 *
 * @constructor
 * @param {string} text - The text of the Instruction
 */
function Instruction(text)
{
   "use strict";
   
   this.text = text;   
}

/**
 * Display this Instruction (in a popup window)
 *
 * (Required by the Step interface)
 */
Instruction.prototype.display = function()
{
   "use strict";

   window.alert(this.text);   
};

        

The Recipe Class

ecmascriptexamples/composite/Recipe.js
        /**
 * An encapsulation of a Recipe
 *
 * @constructor
 * @param {string} title - The title of the Recipe (e.g., "Prepare toast")
 */
function Recipe(title)
{
   "use strict";
   
   this.title = title;   
   this.steps = new Array();   
}

/**
 * Add a Step to this Recipe
 *
 * Note: Because we are using the Composite Pattern, the Recipe class
 * implements the Step. So, a Recipe can be added
 * to a Recipe (as can any other class that implements the interface).
 *
 * @param {Step} step - The Step to add
 */
Recipe.prototype.add = function(step)
{
   "use strict";

   this.steps.push(step);   
};



/**
 * Display this Recipe (in a sequence of popup windows)
 *
 * (Required by the Step interface)
 */
Recipe.prototype.display = function()
{
   "use strict";

   var details, i;

   details = window.confirm(this.title+". \n Do you need details?");

   if (details){
      for (i=0; i<this.steps.length; i++){
         this.steps[i].display();
      }
      window.alert(this.title + ": Complete!");
   }
};


        

The Driver

ecmascriptexamples/composite/Driver.html
        <!DOCTYPE html>
<html>
  <head>
    <script src="Instruction.js" type="text/javascript"></script>
    <script src="Recipe.js"      type="text/javascript"></script>
  </head>
  <body>
    <script type="text/javascript">
      var i, eggsbenedict, hollandaise, sweetyolks;

      eggsBenedict = new Recipe("Prepare Eggs Benedict");
      hollandaise  = new Recipe("Prepare Hollandaise sauce");
      sweetYolks   = new Recipe("Prepare sweetened egg yolks");

      // Eggs Benedict
      eggsBenedict.add(hollandaise);
      i = new Instruction("Toast an English muffin");
      eggsBenedict.add(i);
      i = new Instruction("Poach eggs until whites are soft");
      eggsBenedict.add(i);
      i = new Instruction("Grill Canadian bacon");
      eggsBenedict.add(i);
      i = new Instruction("Plate the completed dish");
      eggsBenedict.add(i);

      // Hollandaise Sauce
      hollandaise.add(sweetYolks);
      i = new Instruction("Bring 1 inch of water in a saucepan to a simmer");
      hollandaise.add(i);
      i = new Instruction("Place the bowl of sweetened yolks over the pan");
      hollandaise.add(i);
      i = new Instruction("Whisk for 3 to 5 minutes");
      hollandaise.add(i);
      i = new Instruction("Add the butter");
      hollandaise.add(i);
      i = new Instruction("Whisk until butter is incorporated");
      hollandaise.add(i);
      i = new Instruction("Add sugar");
      hollandaise.add(i);
      i = new Instruction("Add salt, lemon juice, and cayenne pepper");
      hollandaise.add(i);

      // Sweet Yolks
      i = new Instruction("Place yolks in a bowl");
      sweetYolks.add(i);
      i = new Instruction("Add 1 teaspoon of water");
      sweetYolks.add(i);
      i = new Instruction("Whisk the yolks until they are light and frothy");
      sweetYolks.add(i);

      eggsBenedict.display();
    </script>
  </body>
</html>