You are here

The Composite Pattern

Download the source for the Composite Pattern or get it on Github.

When dealing with data structured as a tree it is necessary to discriminate between a branch and a leaf, not to mention that the structure may include primitive and complex objects. Handling these structures can require complex code but with an interface we can allow the primitive and complex objects to be treated uniformly and simplify the code. The Composite Pattern allows us to do just that by using the same base component to construct our primitive and higher level objects, making them interchangeable; this sort of structure is used to represent part-whole hierarchies.

A good example of this pattern can be seen in a website’s navigation menu: a typical navigation menu might be made up of buttons and submenus of buttons. In order to build our menu we will first need to create our base object. For this we could use an interface but I have chosen to use an abstract class so that I don’t have to explicitly define the base methods in subclasses, they will all by default throw an “Unsupported Operation” exception when called:


abstract class NavComponent  {
	public function add($navComponent)  {
	    throw new Exception('UnsupportedOperationException');
	}
	
	public function remove($navComponent)  {
	    throw new Exception('UnsupportedOperationException');
	}
	
	public function getChild($key)  {
	    throw new Exception('UnsupportedOperationException');
	}
		
	public function getText()  {
	    throw new Exception('UnsupportedOperationException');
	}
	
	public function getLink()  {
	    throw new Exception('UnsupportedOperationException');
	}
		
	public function display()  {
	    throw new Exception('UnsupportedOperationException');
	}
}

Some of those methods should be pretty self-explanatory: getText() will return the menu/button name for example. Not all of the methods will be used by the different objects composing our menu but by having all of our objects built this way we have a great deal of flexibility in the way we make our menus. A menu, at the very least, will need buttons so we’ll make that next:


class NavButton extends NavComponent  {
	private $_text;
	private $_link;
	
	public function __construct($text, $link)  {
		$this->_text = $text;
		$this->_link = $link;
	}
	
	public function getText()  {
		return $this->_text;
	}
	
	public function getLink()  {
		return $this->_link;
	}
	
	public function display()  {
		echo '<a href="' . $this->_link .
			'" title="' . $this->_text .
			'">' . $this->_text . '</a><br/>';
	}
}

As you can see we only really needed a few of the component methods to build our buttons. We can now use our button and create a menu…

Being the more complex object in our part-whole hierarchy, the navigation menu will require that more methods be defined. Our menu will composed of components so we will need an array to store them in as well as the supporting add(), remove(), and getChild() methods. We will be treating the $_components array like a stack for the purpose of keeping the menu ordered:


class NavMenu extends NavComponent  {
	private $_components = array();
	private $_text;
	
	public function __construct($text)  {
		$this->_text = $text;
	}
	
	public function add($navComponent)  {
		array_push($this->_components, $navComponent);
	}
	
	public function remove($navComponent)  {
		if(in_array($navComponent, $this->_components))  {
			$key = array_search($navComponent, 
				$this->_components);
			$this->_components[$key] = NULL;
			$this->_components = array_filter(
				$this->_components);
		}
	}
	
	public function getChild($key)  {
		return $this->_components[$key];
	}
		
	public function getText()  {
		return $this->_text;
	}
	
	public function display()  {
		echo "
"
. $this->_text . "<br/>"; echo "----------------<br/>"; $itr = new NavIterator($this->_components); while($itr->hasNext()) { $obj = $itr->next(); $obj->display(); } echo "----------------<br/><br/>"; } }

Nothing out of the ordinary in the above however the display functionality of our menu is definitely much different than it was for the button. It works by iterating over list of components, calling each component’s display() method as it goes, if a component happens to be another menu it then starts to call it’s component’s display() methods and so on to infinity and beyond. Recursion is a beautiful thing. We’re also using something called a NavIterator to traverse the list of components…

Iterators are a great way to encapsulate looping over groups of objects without worrying about how the objects are actually implemented, check my previous post on the Iterator Pattern for more. Because I already have a SampleIterator interface defined we’ll use that:


interface SampleIterator  {
	public function hasNext();
	public function next();
}

For our NavIterator we’ll need to have an array to store the component items being iterated over, the rest is pretty straightforward:


class NavIterator implements SampleIterator  {
	private $_items = array();
	private $_position = 0;
	
	public function __construct($items)  {
		$count = 0;
		
		if(is_array($items))  {
			foreach($items as $obj)  {
				$this->_items[$count] = $obj;
				$count++;
			}
		}
	}
	
	public function hasNext()  {
		if($this->_position >= count($this->_items) ||
		    $this->_items[$this->_position] == NULL)  {
			return false;
		} else  {
			return true;
		}
	}
	
	public function next()  {
		$item = $this->_items[$this->_position];
		$this->_position += 1;
		return $item;
	}
}

With all of our components and supporting objects built let’s bring it all together…

We’ll start by creating a menu to serve as a submenu by making an array of buttons and adding them using a simple loop. For our $menu we can the make a second array with buttons and our just created $submenu in the 7th position:


function __autoload($class_name) {
	if(file_exists('classes/' . $class_name . '.class.php'))  {
		require_once 'classes/' . 
			$class_name . '.class.php';
	} elseif(file_exists('classes/' . 
			$class_name . '.interface.php'))  {
		require_once 'classes/' . 
			$class_name . '.interface.php';
	}
}

//create a menu to be used as a component
$submenu = new NavMenu('submenu_01');
$submenuData = array(new NavButton('button_07a','7a'), 
		      new NavButton('button_07b','7b'), 
		      new NavButton('button_07c','7c'), 
		      new NavButton('button_07d','7d'), 
		      new NavButton('button_07e','7e'));
foreach($submenuData as $obj)  {
	$submenu->add($obj);
}

//create our main menu of 10 components, adding the submenu in the
//7th position
$menu = new NavMenu('menu');
$menuData = array(new NavButton('button_01','1'), 
		   new NavButton('button_02','2'), 
		   new NavButton('button_03','3'), 
		   new NavButton('button_04','4'), 
		   new NavButton('button_05','5'), 
		   new NavButton('button_06','6'), 
		   $submenu, 
		   new NavButton('button_08','8'), 
		   new NavButton('button_09','9'), 
		   new NavButton('button_10','10'));
foreach($menuData as $obj)  {
	$menu->add($obj);
}

//display the menu
$menu->display();

You should get something like:

menu ---------------- button_01 button_02 button_03 button_04 button_05 button_06
submenu_01 ---------------- button_07a button_07b button_07c button_07d button_07e ----------------
button_08 button_09 button_10 ----------------

With a little bit of modification, some CSS and JavaScript, this could be a pretty functional navigation menu that could be limitless in bounds with nested menus of menus of menus of menus of menus…

Download the source for the Composite Pattern or get it on Github.

Download the source for the Simple Factory Pattern or get it on Github.