组合模式:
将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。从定义中可以得到使用组合模式的环境为:在设计中想表示对象的“部分-整体”层次结构;希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。
组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。
如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。
组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?
一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化(如下图所示)。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。
另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法(如下图所示)。这样就避免了
上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。
在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以
使用空处理或者异常报告的方式来解决。
优缺点
从上面的举例中可以看到,组合模式有以下优点:
1)使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的
是单个对象还是整个组合结构,这就简化了客户端代码。
2)容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。这一点符合开闭
原则的要求,对系统的二次开发和功能扩展很有利!
当然组合模式也少不了缺点:组合模式不容易限制组合中的构件。
1、Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,
使得客户代码可以一致的处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。
2、将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的
对象接口——而非对象容器的复杂内部实现结构——发生依赖关系,从而更能“应对变化”。
3、Composite模式中,是将“Add和Remove的和对象容器相关的方法”定义在“表示抽象对象的Component类”
中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔
细权衡结构,这又是必须付出的代价。
4、Composite模式在具体实现中,可以让父对象中的字对象反向追溯:如果父对象有频繁的遍历需求,可使
用缓存技巧来改善效率
class component {
function descript(){}
public function add(component $com){}
public function remove(component $com){}
}
class dirComposite extends component{
private $arrays=array();
function descript(){
echo "这是一枝干";
}
function add(component $com){
if(in_array($com,$this->arrays,true)){
return;
}
$this->arrays[]=$com;
return count($this->arrays);
}
function check($a,$b){
return( $a === $b )?0:1;
}
function remove(component $com){
$this->arrays=array_udiff($this->arrays,array($com),$this->check( $a , $b ));
}
}
class fileLeaf extends component{
function descript(){
echo "这是一叶枝";
}
}
class client {
static function main(){
$dir=new dirComposite();
$file1=new fileLeaf();
$file2=new fileLeaf();
print_r($dir->add($file1));
}
}
client::main();