Composite Pattern

Used to treat single objects or collections of objects in the same way

Compositions are used to create nested structures of nodes

  • a node may be a single node (leaf) or a container of nodes
  • the ability to iterate through the composite beginning from any node and moving up the tree

What we will be doing:

  • children with no children are leafs
  • children with kids are containers
  • Step 1 – Page: node.js

    
    // JavaScript Document
    define(function () {
    		'use strict';
    		
    		var Person = function (name) { //set up Person object constructor
    			this.name = name; //add name to a property of the object
    			this.children = []; //add children as property and set to empty aray
    			this.parent = null;	//add parent as property as set to null
    		};
    		
    		Person.prototype.addChild = function (child) { //set up method to add children to Person object
    			this.children.push(child);	//push the child arguement into the children array for the object
    			child.parent = this; //create a reciprocal link by setting current person as parent of child passed to the method.  We need this reciprocal link so we can traverse up and down the tree
    		};
    		
    		Person.prototype.traverseUp = function () { //set up method to traverse up
    			if (this.parent) { //check whether current object has parent
    				console.log(this.name + ' is the child of ' + this.parent.name); //if it does, log out a message
    				this.parent.traverseUp(); //then invoke traverseUp method of parent
    			} else { // if there are no parents
    				console.log(this.name + ' is the root node'); //we then know this is a root node
    			}
    		};
    		
    		Person.prototype.traverseDown = function () { //set up traverseDown
    			if (this.children.length) { //check for children
    				this.children.forEach(function (child) { //if so, iterate through children collection
    							console.log(this.name + ' is the parent of ' + child.name); //send out log statement
    							child.traverseDown(); //then invoke traverseDown on child
    				}, this);//set the context for the forEach method, so inside the handler, this still refers to current person objects
    			} else { //if no children
    				console.log(this.name + ' is a leaf node');	//then object is a leaf node
    			}
    		};
    		return Person; //return the person constructor
    });
    

    Step 2 – Page: init.js

    
    define(function(require) {
    	'use strict';
    
    	return {
    		init: function() {
    			
    			var Node = require('composite/node'), //require in node.js
    				root = new Node('Fred'), //set up nodes, al nodes are created in same way
    				child1 = new Node('John'),
    				child2 = new Node('Jane'),
    				child3 = new Node('Jack'),
    				child4 = new Node('Jill'),
    				child5 = new Node('James'),
    				child6 = new Node('Jess')
    				
    				root.addChild(child1); //add two children to root node, then leave child1 as leaf
    				root.addChild(child2);
    				
    				child2.addChild(child3); //add child nodes to child2, making it a container
    				child2.addChild(child4);
    				
    				child4.addChild(child5); //leave child3 as leaf, and make child4 a container with one child
    				
    				child5.addChild(child6); //child5 is container, and child6 is lowest leaf on the tree
    				
    				root.traverseDown(); //displays entire tree
    				root.traverseUp(); //root is the top level, so returns that root is a root node
    				
    				child6.traverseUp(); //displays entire tree
    				child6.traverseDown(); //bottom level, so returns that Jess is a leaf node with no children
    		}
    	};
    });
    

    Step 3 – Page: main.js

    
    // JavaScript Document
    require (
    	['composite/init'],
    	function (composite) {
    			'use strict';
    	
    			var examples = {
    					
    					composite: composite
    					
    				};
    			
    			window.runExample = function (example) {
    				examples[example].init();
    			};
    	}
    );
    
    

    Conclusion

    Main purpose of composite pattern is to allow single objects or collections of objects to be used in the same way

    • we don’t need to know if object is container or leaf, we can process it the same way.