单例模式和工厂模式都属于创建型模式:它们被用来产生一个或多个对象。另外一种设计模式的分类叫做结构型模式。这些模式比较适合用于当需要使用一个非传统的类结构或者一个现有的类结构的修改版本的时候。为了进一步介绍结构性模式,我们来看一看组合模式(Composite pattern)。
一种表明可能要使用组合模式的迹象是,我们正在处理的是一个树状的数据结构。
要实现组合模式,通常会从一个抽象的基类开始。这个基类会被不同的子类扩展。基类需要知道增加或者移除“叶子”(也就是组合的条目)的方法。基类同时也需要知道这个组合或者它的子元素需要做的功能。
为了展示组合模式的一种实现方式,我们举个Department-Employee的例子。这里有两种工作单元的类型:雇员和团队,团队由雇员组成。然后再分配工作给他们完成。
abstract class WorkUnit {
protected $tasks = array();
protected $name = NULL;
function __construct($name) {
$this->name = $name;
}
function getName() {
return $this->name;
}
abstract function add(Employee $e);
abstract function remove(Employee $e);
abstract function assignTask($task);
abstract function completeTask($task);
}
class Team extends WorkUnit {
private $_employees = array();
function add(Employee $e) {
$this->_employees[] = $e;
echo '<p>'.$e->getName().'加入团队'.$this->getName().'</p><br>';
}
function remove(Employee $e) {
$index = array_search($e, $this->_employees);
unset($this->_employees[$index]);
echo '<p>'.$e->getName().'离开团队'.$this->getName().'</p><br>';
}
function assignTask($task) {
$this->tasks[] = $task;
echo '<p>一个新任务:'.$task.'已分配给团队'.$this->getName().'</p><br>';
}
function completeTask($task) {
$index = array_search($task, $this->tasks);
unset($this->tasks[$index]);
echo '<p>任务:'.$task.'已被团队'.$this->getName().'完成</p><br>';
}
}
class Employee extends WorkUnit {
function add(Employee $e) {
return false;
}
function remove(Employee $e) {
return false;
}
function assignTask($task) {
$this->tasks[] = $task;
echo '<p>一个新任务:'.$task.'已分配给队员'.$this->getName().'</p><br>';
}
function completeTask($task) {
$index = array_search($task, $this->tasks);
unset($this->tasks[$index]);
echo '<p>任务:'.$task.'已被队员'.$this->getName().'完成</p><br>';
}
}
将其保存为:workunit.php
创建测试程序:
require('workunit.php');
$alpha = new Team('Alpha');
$tom = new Employee('Tom');
$john = new Employee('John');
$alpha->add($tom);
$alpha->add($john);
$alpha->assignTask("任务1");
$alpha->assignTask("任务2");
$tom->assignTask("任务1");
$john->assignTask("任务2");
$tom->completeTask("任务1");
$alpha->completeTask("任务1");
$alpha->remove($john);
运行结果:
总结一下:在组合模式中,允许一个类像另一个类那样使用,即便一个类可能由另一种类类型组合而成。