User Tools

Site Tools


php:composite

COMPOSITE PATTERN

What is it?

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.

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

In our example we'll try to make use of an abstract GroupManager. Based on it, we'll expand two different types of classes: single workers and groups of workers (which can be single workers only, or mixed with other groups as well).

So, we start to define our abstract class with some useful methods:

  • printName - displays the worker's name; if it's an empty group then display just the string “Empty Group”
  • addWorker - adds to the group a single worker of a group of workers
  • getWorkersCount - how many workers are in a group (count only workers in the tree and not the subgroups)
  • setName - pretty self-explanatory

Abstract Class GroupManager

abstract class GroupManager {
    protected $worker_name; // makes the difference between an empty group or a single worker
    protected $workersArr = array();
 
    public function printName() {
        if (count($this->workersArr)) {
            foreach ($this->workersArr as $w) {
                $w->printName();
            }
        } else {
            $name = ($this->worker_name) ? $this->worker_name : "Empty Group";
            printf("%s\n", $name);            
        }
    }
 
    public function addWorker(GroupManager $oneWorker) {
        array_push($this->workersArr, $oneWorker);
    }
 
    public function getWorkersCount() {
        $total = 0;
 
        if (count($this->workersArr)) {
            foreach ($this->workersArr as $worker) {
                $total += $worker->getWorkersCount();
            }
        } else {
            $total = ($this->worker_name) ? 1 : 0;
        }
 
        return $total;
    }
 
    public function setName($name) {
        $this->worker_name = $name;
    }
}

Now, we implement this in two different classes, also similar (the difference is in the value of the $name variable):

SingleWorker class

class SingleWorkerClass extends GroupManager {
    function __construct($name) {
        parent::setName($name);
    }
}
 
class MultiWorkerClass extends GroupManager {
    function __construct($name = "") {
        parent::setName($name); 
    }
}

And some real usage of it:

Usage

echo "SINGLE WORKER CASE: \n";
$single1 = new SingleWorkerClass("John Doe");
$single1->printName();
printf("How many: %d \n", $single1->getWorkersCount());
 
echo "SINGLE WORKER CASE: \n";
$single2 = new SingleWorkerClass("Jane Doe");
$single2->printName();
 
echo "CREATING GROUP OF 2: \n";
$multi1 = new MultiWorkerClass();
$multi1->printName();
$multi1->addWorker($single1);
$multi1->addWorker($single2);
$multi1->printName();
printf("How many: %d \n", $multi1->getWorkersCount());
 
echo "CREATING BIG GROUP (GROUP OF 2 + ONE SINGLE WORKER): \n";
$single3 = new SingleWorkerClass("Rambo");
$multi2 = new MultiWorkerClass();
$multi2->addWorker($multi1);
$multi2->addWorker($single3);
$multi2->printName();
printf("How many: %d \n", $multi2->getWorkersCount());

php/composite.txt · Last modified: 2013/03/16 17:40 (external edit)