文章目录
一、什么组合模式
组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
二、为什么需要组合模式
-
简化客户端代码:组合模式通过将对象组织成树形结构,使得客户端可以一致地对待单个对象和组合对象。客户端无需关心处理的是单个对象还是组合对象,从而简化了客户端的代码。
-
提供一致的操作接口:组合模式定义了一致的操作接口,使得客户端可以透明地操作单个对象和组合对象。客户端无需关心具体是哪个对象,只需要调用相同的方法即可。
-
支持递归组合:组合模式支持递归组合,即一个组合对象可以包含其他组合对象作为子节点。这样可以方便地处理复杂的层次结构,使得系统更加灵活和可扩展。
-
简化添加新对象:由于组合模式使用了统一的接口,添加新的对象变得非常简单。无论是添加单个对象还是组合对象,都只需要实现相同的接口即可。
-
提高代码复用性:组合模式可以通过递归组合的方式复用已有的对象。通过将对象组织成树形结构,可以灵活地复用已有的对象,从而提高代码的复用性。
三、组合模式的实现原理
- 定义一个抽象基类(Component):该类是组合中所有对象的共同接口,声明了一些操作方法,例如添加、删除、获取子节点等。
- 定义叶子类(Leaf):表示组合中的叶子节点,它没有子节点,实现了抽象基类中的操作方法。
- 定义容器类(Composite):表示组合中的容器节点,它可以包含子节点,实现了抽象基类中的操作方法。容器类中通常会有一个子节点列表用于存储子节点。
- 在容器类中实现对子节点的操作方法:例如添加、删除、获取子节点等。这些操作方法可以递归地调用子节点的相应方法,从而实现对整个树形结构的操作。
- 客户端使用组合模式:客户端可以通过抽象基类来统一对待单个对象和组合对象,从而简化了客户端的代码。客户端可以通过调用操作方法来对整个树形结构进行操作。
四、组合模式的应用场景
- 当需要表示对象的部分-整体层次结构,并且希望客户端能够以统一的方式处理单个对象和对象组合时,可以使用组合模式。
- 当希望忽略对象组合和单个对象之间的差异,统一对待它们时,可以使用组合模式。
- 当希望在不同层次上对对象进行操作,而不需要关心对象是单个对象还是对象组合时,可以使用组合模式。
五、组合模式的代码实现
cpp
//+------------------------------------------------------------------+
//| structure |
//+------------------------------------------------------------------+
//
// |Client|----->| Component |*<------------------+
// |-----------------| |
// |Operation() | |
// |Add(Component) | |
// |Remove(Component)| |
// |GetChild(int) | |
// ^ |
// | |
// +-------+-----------+ |
// | | nodes |
// | Leaf | | Composite |o------+
// |-----------| |-------------------|
// |Operation()| |Operation() |
// | for all n in nodes|
// | n.Operation() |
// |Add(Component) |
// |Remove(Component) |
// |GetChild(int) |
//
//+------------------------------------------------------------------+
//| typical object structure |
//+------------------------------------------------------------------+
//
// +---->|aLeaf|
// |
// |aComposite|-----+---->|aLeaf| +---->|aLeaf|
// | |
// +---->|aComposite|----+---->|aLeaf|
// | |
// +---->|aLeaf| +---->|aLeaf|
//
// 组件
class Component
{
public:
virtual void Operation(void)=0;
virtual void Add(Component*)=0;
virtual void Remove(Component*)=0;
virtual Component* GetChild(int)=0;
Component(void);
Component(string);
protected:
string name;
};
Component::Component(void) {}
Component::Component(string a_name):name(a_name) {}
#define ERR_INVALID_OPERATION_EXCEPTION 1
// 向叶添加/删除组件时出现用户错误
// 表示>叶对象<合成
// 没有孩子
// 定义>行为>组合中的基本体对象
class Leaf:public Component
{
public:
void Operation(void);
void Add(Component*);
void Remove(Component*);
Component* GetChild(int);
Leaf(string);
};
void Leaf::Leaf(string a_name):Component(a_name) {}
void Leaf::Operation(void) {Print(name);}
void Leaf::Add(Component*) {SetUserError(ERR_INVALID_OPERATION_EXCEPTION);}
void Leaf::Remove(Component*) {SetUserError(ERR_INVALID_OPERATION_EXCEPTION);}
Component* Leaf::GetChild(int) {SetUserError(ERR_INVALID_OPERATION_EXCEPTION); return NULL;}
// 定义>具有子级的组件的行为
// 存储>子组件
// 在组件接口中实现>子相关操作>
// 组合
class Composite:public Component
{
public:
void Operation(void);
void Add(Component*);
void Remove(Component*);
Component* GetChild(int);
Composite(string);
~Composite(void);
protected:
Component* nodes[];
};
Composite::Composite(string a_name):Component(a_name) {}
//+------------------------------------------------------------------+
//| participants > composite |
//+------------------------------------------------------------------+
Composite::~Composite(void)
{
int total = ArraySize(nodes);
for (int i=0; i<total; i++)
{
Component* i_node=nodes[i];
if (CheckPointer(i_node)==1)
{
delete i_node;
}
}
}
//+------------------------------------------------------------------+
//| participants > composite |
//+------------------------------------------------------------------+
void Composite::Operation(void)
{
Print(name);
int total = ArraySize(nodes);
for (int i=0; i<total; i++)
{
nodes[i].Operation();
}
}
//+------------------------------------------------------------------+
//| participants > composite |
//+------------------------------------------------------------------+
void Composite::Add(Component *src)
{
int size = ArraySize(nodes);
ArrayResize(nodes,size+1);
nodes[size] = src;
}
//+------------------------------------------------------------------+
//| participants > composite |
//+------------------------------------------------------------------+
void Composite::Remove(Component *src)
{
int find=-1;
int total=ArraySize(nodes);
for (int i=0; i<total; i++)
{
if (nodes[i]==src)
{
find=i;
break;
}
}
if (find>-1)
{
ArrayRemove(nodes,find,1);
}
}
//+------------------------------------------------------------------+
//| participants > composite |
//+------------------------------------------------------------------+
Component* Composite::GetChild(int i)
{
return nodes[i];
}
//+------------------------------------------------------------------+
//| interface for patterns |
//+------------------------------------------------------------------+
interface ClientInterface
{
string Output(void);
void Run(void);
};
//+------------------------------------------------------------------+
//| interface for patterns |
//+------------------------------------------------------------------+
void Run(ClientInterface* client) //launches a pattern
{
printf("---\n%s",client.Output()); //print pattern header
client.Run(); //execute client collaborations
delete client; //exit
}
// 通过组件接口操作组合中的对象
class Client:public ClientInterface
{
public:
string Output(void);
void Run(void);
};
string Client::Output(void) {return __FUNCTION__;}
//+------------------------------------------------------------------+
//| collaborations |
//+------------------------------------------------------------------+
void Client::Run(void)
{
Component* root=new Composite("root"); //make root
//---make components
Component* branch1=new Composite(" branch 1");
Component* branch2=new Composite(" branch 2");
Component* leaf1=new Leaf(" leaf 1");
Component* leaf2=new Leaf(" leaf 2");
//---build tree
root.Add(branch1);
root.Add(branch2);
branch1.Add(leaf1);
branch1.Add(leaf2);
branch2.Add(leaf2);
branch2.Add(new Leaf(" leaf 3"));
//---check
printf("tree:");
root.Operation();
//---change tree
root.Remove(branch1); //remove whole branch
//---check
printf("tree after removal of one branch:");
root.Operation();
//---finish
delete root;
delete branch1;
}
//
void OnStart()
{
Run(new Composite::Client);
}
//+------------------------------------------------------------------+
//| output |
//+------------------------------------------------------------------+
// Structural::Composite::Client::Output
// tree:
// root
// branch 1
// leaf 1
// leaf 2
// branch 2
// leaf 2
// leaf 3
// tree after removal of one branch:
// root
// branch 2
// leaf 2
// leaf 3