将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
处理树中的每个节点时,其实不用考虑他是叶子节点还是根节点。即模糊了简单元素和复杂元素的概念,客户端可以像处理简单元素一样来处理复杂元素。
或者说,复杂元素也是一种简单元素,处理简单元素与复杂元素的操作是一致的。这类似于cocos中的Node及其派生类。
例如,三角形,正方形,圆形,这都属于shape。然后,两个三角形组合成一个新的图形,该图形依然是一个shape,处理方式与简单图形所构成的shape并没有什么不同。
组合模式可以不提供父对象的管理函数,但是必须在合适的时候提供子对象的管理函数。
组合模式有两种:
① 透明方式
所有元素都具有统一的接口,包括管理子类对象的函数。然而,一些叶节点是不具有子类的,也就不需要管理子类的函数。但是为了统一,无论是叶节点还是树节点,都具有统一的函数。
这样并不安全。因为若对叶节点调用了此类函数,可能会出错。
② 安全方式
叶节点不具有管理子类的函数。这样可以有效避免①中出错的问题。
但是这样也就意味着叶节点与其非叶节点会有不同的接口,不够透明。
下面的示例代码采用安全模式(实际上依然不安全,因为并没有屏蔽掉叶节点对子成员的接口):
1. 定义抽象基类,用于规定所有元素的标准接口
class Component
{
public:
virtual void Operation() = 0;
virtual void Add(Component*);
virtual void Remove(Component*);
virtual Component* GetChild(int index);
};
2. 从抽象基类派生两种元素:叶节点元素与非叶结点元素
//叶结点:不含有子组件的类
class Leaf :public Component
{
public:
virtual void Operation();
};
//非叶节点:含有子组件的类
class Composite :public Component
{
public:
void Operation();
void Add(Component*);
void Remove(Component*);
Component* GetChild(int index);
private:
//用vector来保存子组件
vector<Component*> m_ComVec;
};
3. 用户使用
void main()
{
Composite* pRoot = new Composite();
pRoot->Add(new Leaf());
Leaf* pLeaf1 = new Leaf();
Leaf* pLeaf2 = new Leaf();
pLeaf1->Operation();
Composite* pCom = new Composite();
pCom->Add(pLeaf1);
pCom->Add(pLeaf2);
pCom->Operation();
pRoot->Add(pCom);
pRoot->Operation();
}
可见,对于用户而言,所有节点的差异是模糊的。