Composite

组合

组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

适用性

  • 你想表示对象的部分-整体层次结构。
  • 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

示例情境

很多种不同的菜单,但又都是菜单。
Composite Scenario

典型的Composite对象结构

Composite Typical Structure

结构

Composite Class 1
Composite Class 2

Component - 为组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理Component的子组件。(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
Leaf - 在组合中表示叶节点对象,叶节点没有子节点。在组合中定义图元对象的行为。
Composite - 定义有子部件的那些部件的行为。存储子部件。在Component接口中实现与子部件有关的操作。
Client - 通过Component接口操纵组合部件的对象。

协作:
用户使用Component类接口与组合结构中的对象进行交互。如果接受者是一个叶节点,则直接处理请求。如果接受者是Composite,它通常将请求发送给它的子部件,在转发请求之前/之后可能执行一些辅助操作。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <vector>
#include <algorithm>
//---------------------------------------------------
class Component
{
public:
virtual void operation(){}
virtual void add(Component* m)
{

m_children.push_back(m);
}
virtual void remove(Component* m)
{

m_children.erase(std::remove(m_children.begin(), m_children.end(), m), m_children.end());
}
virtual Component* get_child(int n)
{

if (n >= m_children.size()) return NULL;
return m_children[n];
}
protected:
std::vector<Component*> m_children;
};
//---------------------------------------------------
class Leaf : public Component
{
public:
virtual void operation()
{

std::cout<<"I'm Leaf."<<std::endl;
}
};
//---------------------------------------------------
class Composite : public Component
{
public:
virtual void operation()
{

std::cout<<"In the Composite: "<<std::endl;
for (std::vector<Component*>::iterator it = m_children.begin(); it != m_children.end(); ++it)
{
if (!(*it)) continue;
(*it)->operation();
}
}
};
//---------------------------------------------------
class Client
{
public:
void test()
{

Composite composite;
Leaf leaf1, leaf2;
composite.add(&leaf1);
composite.add(&leaf2);
composite.operation();
}
};
//---------------------------------------------------
int main()
{

Client c;
c.test();
system("Pause");
}

相关模式

  • 通常部件-父部件连接用于Responsibility of Chain模式。
  • Decorator模式经常与Composite模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有Add、Remove和GetChild操作的Component接口。
  • Flyweight让你共享组件,但不再能引用他们的父部件。
  • Iterator可用来遍历Composite。
  • Visitor将本来应该分布在Composite和Leaf类中的操作和行为局部化。

[1] 设计模式:可复用面向对象软件的基础
[2] Head First 设计模式