<?php
/**
 * 2.4 组合模式
 * 定义:
 *      将对象组合成树形结构以表示“部分整体”的层次结构。
 *      组合模式使得用户对单个对象和组合对象的使用具有一致性
 * 角色:
 *      1. Component角色
 *          职责:它是组合中的对象接口。在适当的情况下,实现
 *                所有类共有接口的默认行为。声明一个接口用于
 *                访问和管理Component的子部件。
 *      2. Leaf角色
 *          职责:在组合中表示叶子节点对象,叶节点没有子节点
 *      3. Composite角色
 *          职责:定义有枝节点行为,用来存储子部件,在Component
 *                接口中失效与子部件有个的操作。比如增加Add
 *                和删除Remove。
 * 优点:
 *      1. 定义了包含基本对象和组合对象的类层次结构;
 *      2. 统一了组合对象和叶子对象;
 *      3. 简化了客户端调用;
 *      4. 更容易扩展.
 * 缺点:
 * 使用场景:
 *      1. 你想表示对象的部分—整体层次结构。
 *      2. 你希望用户忽略组合对象与单个对象的不同,用户将
 *         统一的使用的使用组合结构中的所有对象。
 */

//抽象公司类
abstract class Company{
    protected $name;
    public function __construct($name){
        $this->name=$name;
    }

    abstract public function add(Company $c);
    abstract public function remove(Company $c);
    abstract public function display($depth);
    abstract public function lineofduty();
}

//具体公司类
class ConcreteCompany extends Company{
    private $children=array();
    public function __construct($name){
        parent::__construct($name);
    }
    public function add(Company $c){
        if(! in_array($c, $this->children)){
            $this->children[]=$c;
        }
    }
    public function remove(Company $c){
        if(in_array($c, $this->children)){
            $pos=array_search($c,$this->children);
            unset($this->children[$pos]);
        }
    }
    public function display($depth){
        $str='__';
        for($i=0;$i<$depth;$i++){
            $str.=$str;
        }
        echo $str.$this->name.'<br/>';
        foreach ($this->children as $c) {
            $c->display($depth+1);
        }
    }
    public function lineofduty(){
        foreach ($this->children as $c) {
            $c->lineofduty();
        }
    }
}

//人力资源部
class HRDepartment extends Company{
    public function __construct($name){
        parent::__construct($name);
    }
    public function add(Company $c){}
    public function remove(Company $c){}
    public function display($depth){
        $str='__';
        for($i=0;$i<$depth;$i++){
            $str.=$str;
        }
        echo $str.$this->name.'<br/>';
    }
    public function lineofduty(){
        echo $this->name.':<br/>职责---员工的招聘培训管理'.'<br/><br/>';
    }
}

//财务部
class FinaceDepartment extends Company{
    public function __construct($name){
        parent::__construct($name);
    }
    public function add(Company $c){}
    public function remove(Company $c){}
    public function display($depth){
        $str='__';
        for($i=0;$i<$depth;$i++){
            $str.=$str;
        }
        echo $str.$this->name.'<br/>';
    }
    public function lineofduty(){
        echo $this->name.':<br/>职责---公司财务收支管理'.'<br/><br/>';
    }
}

// 客户端
$root=new ConcreteCompany('北京总公司');
$root->add(new HRDepartment('总公司人力资源部'));
$root->add(new FinaceDepartment('总公司财务部'));

$comp1=new ConcreteCompany('上海华东分公司');
$comp1->add(new HRDepartment('华东分公司人力资源部'));
$comp1->add(new FinaceDepartment('华东分公司财务部'));
$root->add($comp1);

$comp2=new ConcreteCompany('南京办事处');
$comp2->add(new HRDepartment('南京办事处人力资源部'));
$comp2->add(new FinaceDepartment('南京办事处财务部'));
$comp1->add($comp2);

$comp3=new ConcreteCompany('杭州办事处');
$comp3->add(new HRDepartment('杭州办事处人力资源部'));
$comp3->add(new FinaceDepartment('杭州办事处财务部'));
$comp1->add($comp3);

$root->display(1);
$root->lineofduty();