乐趣区

组合模式

简介

组合模式是用在树状结构中,表示部分和整体的层次结构,组合模式使客户端同等对待对象(叶子节点)和对象的组合(容器)。也分为透明组合模式和安全组合模式,透明组合模式实现了父类的所有方法,安全组合模式不实现管理叶子节点的接口。本文只记录透明组合模式。

UML 类图

示例

树状结构在我们软件设计中很常见。例如菜单下面常常会有子菜单。在此我们构造一个使用文件菜单的示例。我们使用 vector 来作为叶子节点的容器。
抽象对象,叶子节点和容器,composite.h

#ifndef COMPOSITE_H
#define COMPOSITE_H

#include <iostream>
#include <vector>
#include <string>
using namespace std;
#define SAFE_DELETE(p) if(p){delete p; p = NULL;}

class CMenu
{
public:
    CMenu(string strName):m_strName(strName){}
    virtual void Add(CMenu* pMenu) = 0;
    virtual void Remove(CMenu* pMenu) = 0;
    virtual CMenu* GetChild(int nIndex) = 0;
    virtual void ShowMenuName(int indent) = 0;
public:
    string m_strName;
};

class CLeafMenu:public CMenu
{
public:
    CLeafMenu(string strName):CMenu(strName){}
    void Add(CMenu* pMenu)
    {cout<<"Leaf can not add."<<endl;}
    void Remove(CMenu* pMenu)
    {cout<<"Leaf can not remove."<<endl;}
    CMenu* GetChild(int nIndex)
    {
        cout<<"Leaf has no child."<<endl;
        return NULL;
    }
    void ShowMenuName(int indent)
    {string str(indent, '-');
        cout<<str<<m_strName<<endl;
    }
};

class CCompositeMenu:public CMenu
{
public:
    CCompositeMenu(string strName):CMenu(strName){}
    void Add(CMenu* pMenu)
    {m_pMenuVec.push_back(pMenu);
    }
    void Remove(CMenu* pMenu)
    {for(vector<CMenu*>::iterator iter = m_pMenuVec.begin(); iter != m_pMenuVec.end(); ++ iter)
        {if(*iter == pMenu)
            {m_pMenuVec.erase(iter);
                SAFE_DELETE(pMenu);
                break;
            }
        }
    }
    CMenu* GetChild(int nIndex)
    {return m_pMenuVec[nIndex];
    }
    void ShowMenuName(int indent)
    {string str(indent, '-');
        cout<<str<<"+"<<m_strName<<endl;
        for(vector<CMenu*>::iterator iter = m_pMenuVec.begin(); iter != m_pMenuVec.end(); ++ iter)
        {(*iter)->ShowMenuName(indent + 1);
        }
    }
public:
    vector<CMenu*> m_pMenuVec;
};

#endif

客户端调用,main.cpp

#include "composite.h"

#define SAFE_DELETE(p) if(p){delete p; p = NULL;}

int main(int argc, char* argv[])
{CMenu* pRootMenu = new CCompositeMenu("File");
    CMenu* pNew = new CCompositeMenu("New");
    CMenu* PNewProject = new CLeafMenu("Project");
    CMenu* pNewSolution = new CLeafMenu("Solution");
    CMenu* pClose = new CLeafMenu("Close");

    pRootMenu->Add(pNew);
    pNew->Add(PNewProject);
    pNew->Add(pNewSolution);
    pRootMenu->Add(pClose);
    pRootMenu->ShowMenuName(1);
    SAFE_DELETE(pClose);
    SAFE_DELETE(pNewSolution);
    SAFE_DELETE(PNewProject);
    SAFE_DELETE(pNew);
    SAFE_DELETE(pRootMenu);
    return 0;
}

输出结果:

-+File
--+New
---Project
---Solution
--Close

退出移动版