C++设计模式10–组合模式

作者: veaxen 分类: 设计模式 发布时间: 2019-02-28 22:53

定义

(GoF《设计模式》):将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

组成

  1. Component 是组合中的对象接口声明,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
  2. Leaf 在组件中表示叶子结对象,叶子结点没有子节点。
  3. Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

UML图如下:

blob.jpg

在Component中声明所有用来管理子对象的方法,其中包括Add、Remove等,这样实现Component接口的所有子类都具备了Add和Remove。
这样做的好处就是叶节点和枝节点对于外界没有区别,它们具备 完全一致的行为 接口。
但问题也很明显,因为Leaf类本身不具备Add()、Remove()方法的 功能,所以实现它是没有意义的。

适用性

以下情况使用Composite模式:

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

例子

我们每天在公司上班,我们的公司其实就是一个树形结构的,最上边是总公司,总公司下面还有很多子公司,而每个子公司有很多部门。这个整个大公司就是一个大树,每个子公司同时也是一个小树。

首先是公司的抽象接口

// 公司抽象类
class Company
{
publicL:
    Company(std::string name)
    : m_name(name)
    {
    }

    virtual ~Company()
    {
    }

    virtual void Add(Company* pCompany) // 增加子公司
    {
    }

    virtual void Show(int depth) = 0;   // 显示部门
protected:
    std::string m_name;
};

公司的实现:

// 公司类
class ConcreteCompany : public Company
{
public:
    ConcreteCompany(std::string name)
    : Company(name)
    {
    }

    virtual ~ConcreteCompany() {};

    void Add(Company* pCompany)
    {
        this->m_companyList.push_back(company);        // 将子公司或者部门加入到公司的列表中
    }

    void Show(int depth)   // 显示公司部门
    {
        for(int pos = 0; pos < depth; pos++)
        {
            std::cout << "-";
        }
        std::cout << this->m_name << std::endl;
        for(std::list<Company*>::iterater it = this->m_companyList.begin();
                it != this->m_comanyList.end(); ++it)
        {
            (*it)->Show(depth + 2);
        }
    }
protected:
    std::list<Company*> m_companyList;   // 下属公司列表
};

接着是财务部门的实现

// 财务部门 
class FinaceDepartment : public Company
{
public :
    FinaceDepartment(std::string name)
    :Company(name)
    {

    }

    virtual ~FinaceDepartment( )
    {
    }

    void Show(int depth)               // 显示公司部门
    {
        for(int pos = 0; pos < depth; pos++)
        {
            std::cout <<"-";
        }
        std::cout <<this->m_name <<std::endl;
    }
};

然后是人力资源部门

// 人力部门 
class HRDepartment : public Company
{
public :
    HRDepartment(std::string name)
    :Company(name)
    {
    }

    virtual ~HRDepartment( ){ };         // 虚析构函数


    void Show(int depth)               // 显示公司部门
    {
        for(int pos = 0; pos < depth; pos++)
        {
            std::cout <<"-";
        }
        std::cout <<this->m_name <<std::endl;
    }

};

最后是客户端代码

int main()
{
    // 总公司
    Company *root = new ConcreteCompany("总公司");

    Company *rootHR = new HRDepartment("人力资源部");
    Company *rootFI = new FinaceDepartment("财务部");
    root->Add(rootHR);
    root->Add(rootFI);

    // 分公司A
    Company *left = new ConcreteCompany("分公司A");
    Company *leftHR = new HRDepartment("分公司A人力资源部");
    Company *leftFI = new FinaceDepartment("分公司A财务部");
    left->Add(leftHR);
    left->Add(leftFI);
    root->Add(left);

    // 分公司B
    Company *right = new ConcreteCompany("分公司B");
    Company *righHR = new HRDepartment("分公司B人力资源部");
    Company *righFI = new FinaceDepartment("分公司B财务部");
    right->Add(righHR);
    right->Add(righFI);
    root->Add(right);


    root->Show(0);


    return 0;
}

执行结果为:

总公司
--人力资源部
--财务部
--分公司A
----分公司A人力资源部
----分公司A财务部
--分公司B
----分公司B人力资源部
----分公司B财务部

上面代码有个缺点就是没有考虑释放内存的问题,这个不是本文的重点,这里就不再赘述。


参考:https://www.cnblogs.com/jiese/p/3168844.html

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据