组合模式(c++实现)

组合模式

定义

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

动机

当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合对象结构中的所有对象时,就应该考虑用组合模式了。

UML类图

场景拆解

以一个大型公司为需求背景,组织我们的代码。一个北京总公司,下面有郑州和西安两个分公司。然后每个公司不管是总公司还是分公司都有自己的人力资源部,IT部和市场部。

源码实现

  • component.h
#ifndef COMPONENT_H
#define COMPONENT_H
#include <QList>

class Component
{
public:
    Component(QString name);
    virtual ~Component();
    virtual void add(Component* com, int depth = 0) = 0;
    virtual void remove(Component* com) = 0;
    virtual void display() = 0;
    virtual void LineOfDuty() = 0;

    QString name();
    void setDepth(int depth);
    int depth();
private:
    QString         m_Name;
    int                 m_Depth;
};

class ConcreteCompany : public Component
{
public:
    ConcreteCompany(QString name);
    virtual ~ConcreteCompany();
    virtual void add(Component* com, int depth = 0);
    virtual void remove(Component* com);
    virtual void display();
    virtual void LineOfDuty();
private:
    QList<Component*> m_ChildCom;
};

class HumanResource : public Component
{
public:
    HumanResource(QString name);
    virtual ~HumanResource();
    virtual void add(Component* com, int depth = 0);
    virtual void remove(Component* com);
     virtual void display();
    virtual void LineOfDuty();
};

class IT : public Component
{
public:
    IT(QString name);
    virtual ~IT();
    virtual void add(Component* com, int depth = 0);
    virtual void remove(Component* com);
     virtual void display();
    virtual void LineOfDuty();
};

class Marketing : public Component
{
public:
    Marketing(QString name);
    virtual ~Marketing();
    virtual void add(Component* com, int depth = 0);
    virtual void remove(Component* com);
     virtual void display();
    virtual void LineOfDuty();
};
#endif // COMPONENT_H

  • component.cpp
/************************************
    * @brief	: 安排一下故事背景:有一个王者农药全国总公司在深圳,现在想要在全国开办事处
    * 1.北京办事处- 招聘部,研发部,市场部
    * 2.郑州办事处- 招聘部,研发部,市场部
    * 3.西安办事处- 招聘部,研发部,市场部
    * and so on...
    * @author	:   wzx
    * @date	:   2020-05-11
    * @project	:  Composite
*************************************/
#include <QDebug>
#include "component.h"

#define DELETEOBJECT(x) if(x) { delete x; x = nullptr; }

Component::Component(QString name):m_Name(name) {}

Component::~Component(){}

QString Component::name()
{
    return m_Name;
}

void Component::setDepth(int depth)
{
    m_Depth = depth;
}

int Component::depth()
{
    return m_Depth;
}

ConcreteCompany::ConcreteCompany(QString name)
    : Component(name)
{

}

ConcreteCompany::~ConcreteCompany()
{
    for(auto com : m_ChildCom)
    {
        DELETEOBJECT(com);
    }
    m_ChildCom.clear();
}

void ConcreteCompany::add(Component* com, int depth)
{
    com->setDepth(depth);
    m_ChildCom.append(com);
}

void ConcreteCompany:: remove(Component* com)
{
    m_ChildCom.removeOne(com);
}

void ConcreteCompany::display()
{
    QString str;
    for(int n = 0; n < depth(); ++n)
        str += "--";
    qDebug() << qPrintable(str)  <<  (name());
    for(auto com : m_ChildCom)
    {
        com->display();
    }
}

void ConcreteCompany::LineOfDuty()
{

}

HumanResource::HumanResource(QString name)
    : Component(name)
{

}

HumanResource::~HumanResource()
{

}

void HumanResource::add(Component* com, int depth)
{
    com->setDepth(depth);
}

void HumanResource::remove(Component* com)
{

}

void HumanResource::display()
{
    QString str;
    for(int n = 0; n < depth(); ++n)
        str += "--";
    qDebug() << qPrintable(str)  <<  (name());
}

void HumanResource::LineOfDuty()
{
    qDebug() << "人力资源部,负责招聘";
}

IT::IT(QString name)
    : Component(name)
{

}

IT::~IT()
{

}

void IT::add(Component* com, int depth)
{
    com->setDepth(depth);
}

void IT::remove(Component* com)
{

}

void IT::display()
{
    QString str;
    for(int n = 0; n < depth(); ++n)
        str += "--";
    qDebug() << qPrintable(str)  <<  (name());
}

void IT::LineOfDuty()
{
    qDebug() << "IT部门,负责写代码";
}

Marketing::Marketing(QString name)
    : Component(name)
{

}

Marketing::~Marketing()
{

}

void Marketing::add(Component* com, int depth)
{
    com->setDepth(depth);
}

void Marketing::remove(Component* com)
{

}

void Marketing::display()
{
    QString str;
    for(int n = 0; n < depth(); ++n)
        str += "--";
    qDebug() << qPrintable(str)  <<  name();
}

void Marketing::LineOfDuty()
{
    qDebug() << "市场部门,负责市场推广";
}

  • main.cpp
#include <QCoreApplication>
#include <QDebug>
#include "component.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Component* root = new ConcreteCompany("北京总部");
    root->setDepth(0);
    root->add(new HumanResource("人力资源部门"), 1);
    root->add(new IT("IT部门"), 1);
    root->add(new Marketing("市场部门"), 1);

    Component* zz = new ConcreteCompany("郑州办事处");
    zz->add(new HumanResource("人力资源部门"), 2);
    zz->add(new IT("IT部门"), 2);
    zz->add(new Marketing("市场部门"), 2);
    root->add(zz, 1);

    Component* xa = new ConcreteCompany("西安办事处");
    xa->add(new HumanResource("人力资源部门"), 2);
    xa->add(new IT("IT部门"), 2);
    xa->add(new Marketing("市场部门"), 2);
    root->add(xa, 1);

    root->display();
    return a.exec();
}

  • 运行结果

“北京总部”

— “人力资源部门”

— “IT部门”

— “市场部门”

— “郑州办事处”

—- “人力资源部门”

—- “IT部门”

—- “市场部门”

— “西安办事处”

—- “人力资源部门”

—- “IT部门”

—- “市场部门”

优点

组合模式定义了包含基本对象和组合对象的类层次结构。基本对象可以组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了。

缺点

参考《大化设计模式》