The Composite Design Pattern in PHP: Part I from Conceptual to Practical

compositionShow Me the Practical!

A defining characteristic of PHP programmers is their practicality. Ironically, because of their practical orientation, they sometimes overlook the practicality of the abstract and conceptual. Focusing too much on a single (albeit quite useful and practical) implementation is like focusing on a single pixel in a graphic image—you can only see the pixel and miss the larger picture. That’s because the focus is in the wrong place. If you want to see the whole picture (the whole pattern and its parts), the individual pixels are not very practical, even though they are the atomic matter in computer graphics. In other posts on this blog, I have stressed the importance of having a complete design pattern with all of the participants a given design pattern is designed to include and provided a look-up table to check the parts list of all of the core patterns the Gang of Four developed. So in selecting an example to launch a discussion of the Composite pattern, I wanted an example with all of its parts. You can download the files and play a sample using the following two buttons:
PlayDownload

However, too much of a love affair with the conceptual and abstract is equally problematic. If you cannot use a pattern to get something accomplished, why waste time with it? Ironically, design patterns were developed solely for practical purposes, but in order to accomplish those practical goals, they had to provide a set of patterns that would be useful for a wide range of certain recurring programming problems. With these concepts in mind, this post begins with a conceptual example to see how the pattern works and then follow it up with a simple more practical example.

Overview

First things first. The class diagram for the Composite design pattern is both very simple, but it hides a real beauty and subtle complexity. Figure 1 shows the basic pattern:

Figure 1: Composite Design Pattern class diagram

Figure 1: Composite Design Pattern class diagram

Before going too far with an example, even an abstract one, consider the simplicity and irony of the pattern. First of all, the Composite implementation of the Component interface looks fairly cut and dried. However, the Leaf participant also implements the interface, but it doesn’t implement all of the abstract methods. It only implements the operation(). So maybe the interface is an abstract class? It doesn’t matter in PHP. If all of the abstract methods of a class that inherits an abstract class are not implemented, you get the following error:

Fatal error: Class Leaf contains 1 abstract method and must therefore be declared abstract or implement the remaining methods

Since you can only declare an abstract method within an abstract class, you really have no choice but to implement it. Likewise with an interface all methods must be implemented; so with this first abstract example, I decided to use an interface instead of an abstract class.

Favoring Composition: A Tattoo for Your Spouse

One of the fundamental principles of design patterns is,

Favor object composition over class inheritance.

Figure 3: Tats for PHP Developers

Figure 3: Tats for PHP Developers

I tried to get my wife to get a tattoo with that piece of wisdom, but she balked at the idea. (I have no idea why; it’d be cool.) If any pattern adheres to that dictum, it’s the Composite pattern. The Composite participants are made up of Leaf primitives. So you can think of Composite implementations as compositions. The Leaf participants have no children. Think of the Leaf participants as parts that can be employed to create Composite participants.

For the longest time, that simple yet fundamental idea eluded me. In part, this was due to the Gang of Four’s intent statement that the pattern was to Compose objets into tree structures to represent part-whole hierarchies. I was too focused on the concept of hierarchy and not enough on compose to really appreciate the importance of the Composite design pattern.

So here, the first thing to do is to realize that the hierarchy is a form of composition. Imagine an automobile assembly plant where you have lots of parts, yet with those parts you can assemble different models of cars. You just have to use different selections of parts to compose the different models. The fact that the parts have a hierarchic arrangement is for efficiency; not the final product itself. Figure two shows what we hope to create in this initial implementation:

Figure 2: Different Compositions from Leaf Selections

Figure 2: Different Compositions from Leaf Selections



A Party of Four

The Composite pattern is pretty simple when you consider the main four participants:

  • Component (IComponent):
    • Declares interface
    • Implements default behavior as appropriate
    • Declare an interface for access and managing its child components
    • Optionally defines an interface for accessing a components parent in the recursive structure and implements it if appropriate.
  • Leaf
    • Represents leaf objects in composition.
    • Defines behavior for primitive objects in the composition.
  • Composite
    • Defines behavior for components having children
    • Stores child components
    • Implements child-related operations in the Component interface
  • Client
    • Manipulates objects in the composition through the Component interface.

Beginning with the Component interface (IComponent), this example uses an interface rather than an abstract class. The example was originally developed by Dr. Chandima Cumaranatunge in ActionScript 3.0 Design Patterns (O’Reilly, 2007), and has been re-written in PHP:

<?php
//IComponent.php
interface IComponent
{
    public function operation();
    public function add(IComponent $comOn);
    public function remove(IComponent $comGone);
    public function getChild($someInt);
}
?>

The key methods in the IComponent interface are operation() and add(IComponent $comOn). The operation() method is a recursive one in the Composite class because it must include all of the child elements in the composed objects. In the Leaf class, the same operation must be implemented, but it is done without recursion because Leaf objects have no children.

The add(IComponent $comOn) method includes type hinting in its parameter. It expects some kind of implementation of the interface. That means that the argument must be either a Composite object or a Leaf object. This is where programming to the interface comes in. The program doesn’t care where the component comes from (a Leaf or Composite); as long as it implements the interface. In these early abstract examples, we’re not implementing the remove(IComponent $comGone) and getChild($someInt) so that we can have a clear focus on what the composition is doing.

Composite

The Composite class in this example has the key features we need to address. Unlike the Leaf class, it can add implemented IComponent objects. These become the children of the Composite class.

<?php
//Composite.php
class Composite implements IComponent
{
    private $sName;
    private $aChildren;
 
    public function __construct($sNodeName)
    {
        $this->sName=$sNodeName;
        $this->aChildren=array();
    }
 
    public function add(IComponent $comOn)
    {
        array_push($this->aChildren,$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 operation()
    {
        echo $this->sName . "<br />";
        foreach($this->aChildren as $elVal)
        {
            $elVal->operation();
        }
    }
}
?>

The operation() method is recursive. It calls itself. The $elVal variable stores $aChildren elements as the operation() method iterates through the $aChildren array. Some of the objects will be Leaf ones and others will be Composite. As a Leaf object is iterated out of the array, it calls the Leaf object method ($Leaf->operation()), while Composite objects call the Composite’s operation() method ($Composite->operation()). To get a better idea of how this crucial operation works, comment out the echo statement first in the Leaf operation and run the program. Then uncomment out the echo statement in the Leaf, and comment out the echo statement in the Composite operation() method. You will see that each Leaf and Composite instance is processed by the operation() method of the corresponding object.

Leaf

The Leaf objects are best viewed as primitives.The Leaf participant in the pattern defines the behavior of the primitives. In this context, “primitives” are some kind of basic building blocks whether primitive data types such as integers, Booleans, or even strings. These can them be composed via the Composite object or be used independent of any composition. The Gang of Four provide an example where different Leaf classes are used to provide different drawing elements, such as lines, circles, and rectangles. These can then be composed to create a picture in the Composite object. While this example only has a single Leaf object, Composites usually have several.

<?php
//Leaf.php
class Leaf implements IComponent
{
    private $sName;
 
    public function __construct($sNodeName)
    {
        $this->sName=$sNodeName;
    }
 
    /* None of this batch of methods are used by Leaf */
    /* 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){}
 
    /* Some userful content is required for the operation */
    public function operation()
    {
        echo $this->sName . "<br />";
    }
}
?>

The only functionally implemented method in the Leaf class is the operation(). You may wonder, Why bother implementing the interface if the bulk of the methods are not implemented? In programming to the interface instead of the implementation, the same interface is used by both Leaf and Composite classes. In requesting them, the Client can request either a primitive or composite object without having to distinguish one from the other. This makes the development of the Client much simpler, and Leaf classes may be added using the existing structure.
Client

<?php
//Client.php
ERROR_REPORTING( E_ALL | E_STRICT );
ini_set("display_errors", 1);
function __autoload($class_name) 
{
    include $class_name . '.php';
}
class Client
{
    private $rootCompos;
 
    public function __construct()
    {
        $this->rootCompos = new Composite("Root");
        $n1=new Composite("-Composite 1");
        $n1->add(new Leaf("--C1:leaf 1"));
        $n1->add(new Leaf("--C1:leaf 2"));
        $this->rootCompos->add($n1);
 
        $n2=new Composite("-Composite 2");
        $n2->add(new Leaf("--C2:leaf 3"));
        $n2->add(new Leaf("--C2:leaf 4"));
        $n2->add(new Leaf("--C2:leaf 5"));
        $this->rootCompos->add($n2);
 
        $this->rootCompos->add(new Leaf("R:leaf 6"));
 
        //Create a node
        $this->rootCompos->operation();
    }
}
$worker=new Client();
?>

Since the example is minimal and abstract, it applies to any language, and after making adjustments for PHP, it works exactly as planned. (In the download, I included two examples; one using an abstract class and and the other an interface.) It’s primary role is to illustrate how the Composite design pattern works and the output shows the flow. In the following output, your can see the hierarchy shown in Figure 2 is generated by the program:

Root
-Composite 1
–C1:leaf 1
–C1:leaf 2
-Composite 2
–C2:leaf 3
–C2:leaf 4
–C2:leaf 5
R:leaf 6

In Part II of this series, we’ll take this same program and add concrete elements to the program for further illustration of what can be done with the Composite. Eventually, we’ll see how this pattern can be used in typical kinds of problems that PHP solves. For now, play around with the pattern, and if you have any comments or possible practical projects you’d consider using it for, send in a comment.

Share

Copyright © 2013 William Sanders. All Rights Reserved.

0 Responses to “The Composite Design Pattern in PHP: Part I from Conceptual to Practical”


  • No Comments

Leave a Reply