Don’t forget to Program to the Interface!
While the primary principle we draw from the Composite pattern is , Favor object composition over class inheritance, as discussed in Part I of the Composite series, another important principle applies here as well. The very first principle of design patterns is, Program to an interface, not an implementation. In a sense this is saying, program to an abstract parent and not a concrete child, but if you understand an interface to be the structure implied in either an interface (as used in the first and in this example) or an abstract class, you can see what the value of that principle is.
In this part, instead of a single leaf and a hierarchy rending output, this example shows how a Composite design with multiple leaves can be used to create a mosaic—which is the essence of composite! The interface (IComponent) is little changed except the string parameter has been removed from the operation() method and replaced (for clarity) with a method named showPix() with no parameters. All of the other methods remain the same. Play the application and download the source code and files to get started:
Follow the Structure; Not the Sequence
To get out of the tar pit of sequential programming, look at the structure and think in terms of using larger structural concepts. Take a look at the three key participants in the Composite pattern, beginning with the key structural participant, the IComponent interface, focusing on their structure as outlined in the interface.
//IComponent.php
interface IComponent
{
public function showPix();
public function add(IComponent $comOn);
public function remove(IComponent $comGone);
public function getChild($someInt);
}
?>
|
As in Part I, the IComponent has four methods to be implemented, and though all four are implemented, only the first two are used for this second part. The focus is still on the idea of composition. The fact that we don’t need the second two right now does not detract from the fact that they (remove() and getChild() methods) unimportant for the pattern; just not for this example.
So the implementation of the the Composite class looks structurally similar to that in Part I, but the constructor function has no node name to identify in a parameter. Likewise, the showPix() method is almost identical to the operation() method in Part I, and only the name of the array has changed from $aChildren to $mosaic. Also, the echo statement is no longer part of the method.
//Composite.php
class Composite implements IComponent
{
private $mosaic;
public function __construct()
{
$this->mosaic=array();
}
public function add(IComponent $comOn)
{
array_push($this->mosaic,$comOn);
}
public function remove(IComponent $comGone)
{
//Code to remove component
}
public function getChild($someInt)
{
//Code to get child by element value
}
//Note: The following method is recursive
public function showPix()
{
foreach($this->mosaic as $tile)
{
$tile->showPix();
}
}
}
?>
|
If you’ve played both Part I and Part II examples of Composite patterns, you know they are very different in what they generate, but the structures for both are virtually identical. Each is combining leaf elements into composite ones. Same structure; different outcomes. That virtually defines code re-use.
Parts is Parts
While the implementation of the Composite class is little unchanged, the number and implementation of the leaf nodes are different. Each leaf class has a single task and no constructor parameter. The unused methods are implemented the same. Each leaf contains an HTML tag to an image. The Composite class stores instances of leaf instances in the $mosaic array and creates rows of images that are aligned to display the tiled image. You can think of each tile in the display as a leaf, and each row a composite of tiles and the entire mosaic as a composite of the three composites that make up the rows.
class Leafr1c1 implements IComponent
{
/* None of this batch of methods are used by leaf participants */
/* However in order to correctly implement the interface */
/* you need some kind of implementation */
public function add(IComponent $comOn){}
public function remove(IComponent $comGone){}
public function getChild($someInt){}
/* Display tile */
public function showPix()
{
echo "
|
Each of the leaf classes is named after a column and row where the tile is to be placed. For example the leaf class to place an image in Row 2, Column 3 of the mosaic is named Leafr2c3. Likewise, the names of the PNG graphic files share the same naming conviction. So Leafr2c3 has the code to display the r2c3.png image file.
The Client
As an integral part of the Composite design pattern, the Client can be seen as the artist who composes the mosaic. He does this by selecting each tile for the rows and arranges them to get the desired picture. Because no string parameter is in the leaf constructors, each leaf added to a composition does not need a name. (In a sense, the title names have been embedded into the leaf names.) The $bigPictue property is the same name as used in the original Client example, except this time, it really will produce a “big picture.” It is the root composition made up of three row compositions that are made up of three leaf elements.
ERROR_REPORTING( E_ALL | E_STRICT );
ini_set("display_errors", 1);
function __autoload($class_name)
{
include $class_name . '.php';
}
class Client
{
private $bigPicture;
public function __construct()
{
$this->bigPicture = new Composite();
$row1=new Composite();
$row1->add(new Leafr1c1());
$row1->add(new Leafr1c2());
$row1->add(new Leafr1c3());
$this->bigPicture->add($row1);
$row2=new Composite();
$row2->add(new Leafr2c1());
$row2->add(new Leafr2c2());
$row2->add(new Leafr2c3());
$this->bigPicture->add($row2);
$row3=new Composite();
$row3->add(new Leafr3c1());
$row3->add(new Leafr3c2());
$row3->add(new Leafr3c3());
$this->bigPicture->add($row3);
//Create a compostion
echo "";
echo "";
echo "";
echo "
|
In this installment, the goal is to show that the Composite design pattern is more than a tree-like hierarchy-making pattern. It is the essence of composition and the Composite design pattern. The mosaic image is a metaphor for the pattern in that it is composed of several compositions and elements within those compositions.
Adding the Final Touches
With two unimplemented methods (remove() and getChild()), in Part III of this series, you will see how they can be used for added flexibility with the Composite design pattern. I’d like to look at the original Gang of Four idea of using the Composite pattern to create a drawing program. Until next time, I welcome any and all comments.
Recent Comments