Categories


Loading feed
Loading feed
Loading feed

PHP Patterns: The Composite Pattern


Introduction

One of the great strengths of pattern oriented design is its viral nature. That is, the way that one pattern tends to create conditions ideal for the application of another pattern, which itself then benefits from yet another. Of course, this is also one of the greatest weaknesses of the approach. Pick the wrong patterns, and you are easily beguiled into a creating a system that is poorly suited for its purpose. Assuming, though, that you select carefully, the complementary nature of many patterns can be useful. As your projects throw up design challenges, you will often find that ideal solutions are already documented in the classic pattern catalogs.

Over the next two articles, I will examine two patterns that work well together. Composite provides a mechanism for grouping multiple components together under a single interface at runtime, and Visitor is a natural way of performing operations across the resulting structure. These patterns can be used in isolation, but they are so naturally suited that they invariably end up in the kitchen together at parties.

Let's begin here with the Composite Pattern.

The Composite Pattern

Composite is a classic Gang of Four pattern. It is probably one of the most aesthetically pleasing patterns in the catalog, due to the interplay it engenders between the static inheritance structure of its components and their dynamic runtime compositional relationships. As you might expect from its name, the Composite pattern exemplifies the principle: favor composition over inheritance. As we shall see, however, inheritance does not only sit on the other side of the coin from composition, we can use inheritance relationships to promote and support composition.

Overview

The Composite pattern provides a single interface that allows a client programmer to work with single component or a collection of components interchangeably. In fact the client code may not even know whether it is manipulating one component, or many. If you are finding this hard to visualize, think of a graphical user interface. It incorporates many components: checkboxes, radio buttons, panes, windows and so on. When you move a window, you also move its contents. Although you are moving multiple components, you don't want to handle all the details yourself, like this:

$window->move();
$pane->move()
$checkbox->move();
$radio->move();
$content->move();

It would be better to simply call move() on $window and have the window object pass the order on to its various components. Composite can help you to create component structures that support propagation of this kind.

The Problem

You are building an application called MyList for managing hierarchies of notes (Note objects). Each Note consists of a title, some text, and any number of other Note objects. With the right interface, this could make a powerful little utility for organizing... well, just about anything you like. Of course, it would need specialized components to represent binary files (Binary), Web content (WebText), and so on.

Here is a graphical representation of a set of notes:

Figure 1

As with the graphical user interface example, you will need to perform operations upon many components at one time. You might need to print note data, for example, and count the number of elements in a structure. Users may want to move notes around, so you should provide for this, which is simple enough, and also you should make it easy to copy parts of the structure from place to place, which is a little harder.

The Composite pattern is appropriate to a relatively clear set of conditions, all of which apply in this case.

Firstly, we want to manage components so that for core operations there is no functional distinction between a collection of objects and a single object. A client must be able to call the same key methods (for example, output(), size()) on either. So you should be able to call output() on a bunch of nested Note objects, in exactly the same way as you are able to call output() on a Binary object which can contain nothing but itself. In fact, an entire collection should be functionally identical in its core interface to a single component. This requirement should be pretty intuitive: a single soldier attacks, as does a battalion; a boat sails, as does a flotilla. It is natural to group items together, and then operate on the collective.

Secondly, we need to be able to select and manipulate a collection of objects easily. A GUI, for example, might support a tear-off menu feature. A user can pull a menu from a menu bar so that it floats as a palette. The sub-components that make up the menu must therefore have the ability to be copied or moved into a new context. In the MyList example, a user may want to rearrange her notes so that a shopping list lives under 'Household' rather than 'General' - the principle is the same.

We need an easily extensible system. Right now we know that MyList needs a particular set of components, but we are reasonably sure that we will add new ones in the future. We should be able to do this with minimum disruption to our application as a whole.

The final sign that a Composite might be a suitable strategy in your code is the presence of, or a clear requirement for, a tree structure. This is in fact part of the Composite implementation, but some sets of components (GUIs, file system representations, XML elements) so obviously lend themselves to this kind of parent/child organization that the chances are you will already have thought about deploying it.

Implementation

So how do we aggregate this simplified set of components (Note, Binary, WebText), and how do we run operations on the resulting structure?

Apart from the client, every component in the Composite pattern belongs to the same type. This is how we can guarantee consistency across collections and individual objects - from an interface point of view there is no difference.

What can be confusing about the Composite pattern is the similarity in structure of the inheritance relationship between classes and the runtime organization of objects.

Apart from the client context, all participants extend a single, usually abstract, component class. This, of course, makes all implementing classes components themselves. The component defines methods for adding and removing other components. Implementing classes come in two flavors: the leaf, which does not accept children and the composite, which does. Figure 2 shows these participants:

Figure 2

Note that, according to this particular interface, both leaves and composites accept children. We will return to this issue later in the article. For now, it's worth remembering that attempting to add a component to a leaf class should result in an exception, or else silent inaction.

Here is the component superclass for the MyList example:

abstract class MyListComponent {
    abstract function 
add(MyListComponent $comp);
    abstract function 
remove(MyListComponent $comp);
    abstract function 
output($level 0);
    abstract function 
number();
}

As you can see, components have two areas of responsibility. Firstly they are concerned with adding, storing and removing other components. For this purpose we define the add() and remove() methods. Secondly, they must perform their core tasks as components. In this example I have defined two operations common to all components: output() and number(). output() is responsible for printing a very basic text representation of the contents of a ListComponent object. number() returns the number of components at and below the current level in the tree.

Here is the Binary class, which is a leaf:

class Binary extends MyListComponent {
    private 
$path;

    function 
__construct($path) {
        if (!
file_exists($path)) {
            throw new 
Exception("'$path' does not exist");
        }
        
$this->path $path;
    }

    function 
add(MyListComponent $comp) {
        return 
$comp;
    }

    function 
remove(MyListComponent $comp) {
        return 
true;
    }

    function 
number() {
        return 
1;
    }

    function 
output($level 0) {
        
$pad $this->pad($level);
        
$basename basename($this->path);
        print 
"{$pad}<< binary: {$basename} >>\n";
    }
}

As is usual in example code, rigor has been sacrificed for clarity. In the real world we would apply more error checking and more sophisticated functionality. The objective here, though, is to keep things simple.

The Binary class is forced by the MyListComponent class to implement add() and remove() methods. However, because this class is a leaf type, those methods do not actually do anything. Binary also implements number() to simply return 1. Since it cannot aggregate any components, it will only ever represent itself.

The output() method prints the name of the file that the class is designed to manage. output() is not designed for multimedia display, so Binary gives information about the file, rather than displaying the file itself. This method, in its various implementations, is therefore useful mainly for information and debugging. I'll look at ways in which presentation code might more usefully engage with our components in the next article in this series.

Things get a little more interesting when we add a composite to the mix. As you saw in figure 2, a composite is responsible for adding, removing and working with child components, as well as performing its own duties. If you have more than one composite type, it's a good idea to create an abstract superclass that implements add() and remove(), as these are not likely to change between composite classes.

Here is an abstract composite class:

abstract class MyListComposite extends MyListComponent {
    protected 
$children = array();

    function 
add(MyListComponent $comp) {
        
$this->children[] = $comp;
        return 
$comp;
    }

    function 
remove(MyListComponent $comp) {
        
$index array_search($comp$this->childrentrue);
        if (
$index === false) {
            return 
false;
        }
        
array_splice($this->children$index1);
        return 
true;
    }

    function 
__clone() {
        
$kids = array();
        foreach (
$this->children as $child) {
            
$kids[] = clone($child);
        }
        
$this->children $kids;
    }

    function 
number() {
        
$total 1;
        foreach (
$this->children as $child) {
           
$total += $child->number();
        }
        return 
$total;
    }
}

There's a lot going on here, but nothing that should cause great brain ache. Obeying the interface laid down in MyListComponent, the add() method accepts a MyListComponent object and adds it to the protected $children array property. remove() reverses this, using array_search() to locate the given element, and array_splice() to remove it. Notice the third Boolean we pass to array_search(). This forces the search to respect type (the equivalent of using === rather then == for comparison).

We have add() return the MyListComponent it has been given. This may seem redundant, but it can make for nicely compact client code. If add() did not return a component, you would have to do this:

$list = new ConcreteMyListComposite('shopping list');
$bread = new ConcreteMyListComposite('bread');
$list->add($bread);

If add() returns its component, we can save a line of code here:

$list = new ConcreteMyListComposite('shopping list');
$bread $list->add(new ConcreteMyListComposite('bread'));

We can even chain multiple additions into a single statement:

$list->add(new ConcreteMyListComposite('bread'))->add(new ConcreteMyListComponent('bread info'));

number() and __clone() both show typical behavior for composite operations. In number() we first set the return value to 1, accounting for the current component. Then we cycle through the $children array, calling number() on each member. Remember that $children is guaranteed to contain MyListComponent objects, thanks to the type hinting in the add() method declaration. The abstract method declaration in MyListComponent ensures that all subclasses will implement the number() method.

__clone() is a magic method. It is automatically called by the Zend Engine when the clone operator is used on an object. The thing to remember about __clone() is that it works after the fact. The $this variable in the method actually refers to the cloned object, not to the original. The initial clone is shallow, however, which means that all references are shared. A cloned MyListComposite object will have its own $children array, but its members will be references to the children that were aggregated by the original object. This could make for some interesting bugs. We overcome the problem by cloning all elements in the $children array. Any children that are composites will do the same to their children, because they will inherit this __clone() method.

Now that I have discussed __clone(), you may wish to consider what happens when a Binary object is cloned. You will end up with two objects pointing to the same file on disk. I will leave this problem as an exercise for the reader.

MyListComposite is abstract because it leaves the implementation of output() to extending classes. For example, here is a class named Note:

class Note extends MyListComposite {
    protected 
$title;
    protected 
$note;

    function 
__construct($title$note null) {
        
$this->title $title;
        
$this->note $note;
    }

    function 
output($level 0) {
        
$pad $this->pad($level);
        print 
"{$pad}{$this->title}\n";
        if (!
is_null($this->note)) {
            print 
"{$pad} - {$this->note}\n";
        }
        foreach (
$this->children as $child) {
            
$child->output($level 1);
        }
    }
}

This simple class manages $title and $note properties. Since it extends MyListComposite, it only needs to implement output(). The mechanism here should be familiar by now. The method prints data for the local class, and then loops through the $children array, calling output() on each child element.

Notice that we call a method called pad(). This is simply a utility operation that generates a set of spaces based on an integer argument. We use this to generate a basic layout when printing our MyList data. The output() method passes an incremented $level variable to its children, so each output() invocation knows about its relative depth. Here is pad(), which is implemented by MyListComponent:

// MyListComponent...

    
function pad($level) {
        
$ret "";
        for (
$x = 0$x $level$x++) {
            
$ret .= "    ";
        }
        return 
$ret;
    }

For the sake of completeness, let's add another MyListComposite object. WebText stores a URL and prints a crudely formatted version of its data when output() is called. Like Note, it then calls output() on its children:

class WebText extends MyListComposite {
    protected 
$title;

    function 
__construct($title$url) {
        
$this->url $url;
        
$this->title $title;
    }

    function 
getText() {
        return 
file_get_contents($this->url);
    }

    function 
output($level 0) {
        
$pad $this->pad($level);
        
$text trim(wordwrap(strip_tags($this->getText()), 50 ));
        
$text preg_replace("/^/m""{$pad}> "$text);
        print 
"{$pad}{$this->title}\n";
        print 
"$text\n";
        foreach (
$this->children as $child) {
            
$child->output($level 1);
        }
    }
}

Figure 3 shows the participants of this system.

Figure 3

[ continued in part 2 of PHP Patterns: The Composite Pattern ]

Digg This!

Comments


Wednesday, November 8, 2006
COMPOSITE PATTERN MODEL
3:19AM PST · Todd Breslow [unregistered]
Saturday, May 5, 2007
STR_REPAT IN PAD FUNCTION
1:44PM PDT · thor84
Monday, April 28, 2008
ORDERING FUNCTIONALITY
2:19AM PDT · troopeer