一、什么组合模式

二、为什么需要组合模式

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

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

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

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

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

三、组合模式的实现原理

  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 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

02-06 07:43