文章目录

    • 一、什么组合模式
    • 二、为什么需要组合模式
    • 三、组合模式的实现原理
    • 四、组合模式的应用场景
    • 五、组合模式的代码实现

一、什么组合模式

组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

二、为什么需要组合模式

  • 简化客户端代码:组合模式通过将对象组织成树形结构,使得客户端可以一致地对待单个对象和组合对象。客户端无需关心处理的是单个对象还是组合对象,从而简化了客户端的代码。

  • 提供一致的操作接口:组合模式定义了一致的操作接口,使得客户端可以透明地操作单个对象和组合对象。客户端无需关心具体是哪个对象,只需要调用相同的方法即可。

  • 支持递归组合:组合模式支持递归组合,即一个组合对象可以包含其他组合对象作为子节点。这样可以方便地处理复杂的层次结构,使得系统更加灵活和可扩展。

  • 简化添加新对象:由于组合模式使用了统一的接口,添加新的对象变得非常简单。无论是添加单个对象还是组合对象,都只需要实现相同的接口即可。

  • 提高代码复用性:组合模式可以通过递归组合的方式复用已有的对象。通过将对象组织成树形结构,可以灵活地复用已有的对象,从而提高代码的复用性。

三、组合模式的实现原理

  1. 定义一个抽象基类(Component):该类是组合中所有对象的共同接口,声明了一些操作方法,例如添加、删除、获取子节点等。
  2. 定义叶子类(Leaf):表示组合中的叶子节点,它没有子节点,实现了抽象基类中的操作方法。
  3. 定义容器类(Composite):表示组合中的容器节点,它可以包含子节点,实现了抽象基类中的操作方法。容器类中通常会有一个子节点列表用于存储子节点。
  4. 在容器类中实现对子节点的操作方法:例如添加、删除、获取子节点等。这些操作方法可以递归地调用子节点的相应方法,从而实现对整个树形结构的操作。
  5. 客户端使用组合模式:客户端可以通过抽象基类来统一对待单个对象和组合对象,从而简化了客户端的代码。客户端可以通过调用操作方法来对整个树形结构进行操作。

四、组合模式的应用场景

  1. 当需要表示对象的部分-整体层次结构,并且希望客户端能够以统一的方式处理单个对象和对象组合时,可以使用组合模式。
  2. 当希望忽略对象组合和单个对象之间的差异,统一对待它们时,可以使用组合模式。
  3. 当希望在不同层次上对对象进行操作,而不需要关心对象是单个对象还是对象组合时,可以使用组合模式。

五、组合模式的代码实现

//+------------------------------------------------------------------+//| 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 voidOperation(void)=0;virtual voidAdd(Component*)=0;virtual voidRemove(Component*)=0;virtual Component* GetChild(int)=0;Component(void);Component(string);protected:stringname;};Component::Component(void) {}Component::Component(string a_name):name(a_name) {}#define ERR_INVALID_OPERATION_EXCEPTION 1// 向叶添加/删除组件时出现用户错误// 表示>叶对象<合成// 没有孩子// 定义>行为>组合中的基本体对象class Leaf:public Component{public:voidOperation(void);voidAdd(Component*);voidRemove(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:voidOperation(void);voidAdd(Component*);voidRemove(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 headerclient.Run(); //execute client collaborationsdelete client; //exit}// 通过组件接口操作组合中的对象class Client:public ClientInterface{public:stringOutput(void);voidRun(void);};string Client::Output(void) {return __FUNCTION__;}//+------------------------------------------------------------------+//| collaborations |//+------------------------------------------------------------------+void Client::Run(void){Component* root=new Composite("root"); //make root //---make componentsComponent* branch1=new Composite(" branch 1");Component* branch2=new Composite(" branch 2");Component* leaf1=new Leaf("leaf 1");Component* leaf2=new Leaf("leaf 2");//---build treeroot.Add(branch1);root.Add(branch2);branch1.Add(leaf1);branch1.Add(leaf2);branch2.Add(leaf2);branch2.Add(new Leaf("leaf 3"));//---checkprintf("tree:");root.Operation();//---change treeroot.Remove(branch1); //remove whole branch//---checkprintf("tree after removal of one branch:");root.Operation();//---finishdelete 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