设计模式(十二)——组合模式

一、组合模式简介

1、组合模式简介

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

组合模式为解决组件之间的递归组合提供了解决的办法,主要分为两个派生类:

    ALeaf是叶子结点是不含有子组件的结点

    BComposite是含有子组件的类

    组合模式有透明组合模式安全组合模式两种模式。

透明组合模式特点:

AComponent中定义了用于访问和管理子构的接口,好处是确保所有的构件类都有相同的接口。

BClient看来,LeafComposite所提供的接口一致,Client可以相同地对待所有的对象。

安全组合模式特点:

Component中不定义任何用于访问和管理子构建的接口,而在 Composite中声明并实现。因为不需要向Leaf提供管理成员对象的接口,对于Leaf来说,Client不可能调用到管理子构件对象的接口。

透明组合模式安全组合模式的区别:

A透明组合模式的缺点是不够安全,因为LeafComposite在本质上是有区别的。Leaf不可能有下一个层级,因此为其提供add()remove()getChild() 等接口没有意义。在运行阶段如果调用这些接口可能会出错(如果没有提供相应的异常处理)。

   B安全组合模式的缺点是不够透明,因为LeafComposite具有不同的接口,且Composite中用于访问和管理子构件的接口没有在Component中定义,因此Client不能完全针对抽象编程,必须有区别地对待LeafComposite

组合模式的UML图:

设计模式(十二)——组合模式_第1张图片

    在Component中声明所有用来管理子对象的方法,其中包括addremovegetChild,实现Component接口的所有子类都具备了addremovegetChild好处就是叶节点和节点对于外界没有区别,具备完全一致的行为接口。但因为Leaf类本身不具备add()remove()getChild()方法的功能,所以Leaf继承的Component基类的addremovegetChild是没有意义的。

2、组合模式角色

Component抽象构件:为组合中的对象声明接口,实现所有类共有接口的默认行为addremovegetChild。声明一个接口用于访问和管理Component 的子部件。

            Component::operatation:定义了各个组件共有的行为接口,由各个组件的具体实现
            Component::add添加一个子组件
            Component::remove::删除一个子组件.
            Component::getChild:获得子组件的指针

Leaf叶子节点:在组合中是叶节点对象,叶节点没有子节点。

Composite枝构件:定义有节点行为,用来存储子部件,重新实现Component接口中与子部件有关的操作,比如addremovegetChildoperation

3、组合模式优缺点

    优点:

A组合模式清晰地定义了包含基本对象(Leaf)和组合对象(Composite)的类层次结构的复杂对象。基本对象可以被组合成更复杂的组合对象,而组合对象又可以被组合,客户代码可以忽略层次的差异,任何用到基本对象的地方都可以使用组合对象方便对整个层次结构进行控制。

B用户不用关心到底是处理一个叶子节点还是处理一个组合组件。

C组合模式让客户可以一致的使用组合结构和单个对象。

D在组合模式中,增加新的叶子构件和容器构件很方便,无须对现有类进行任何修改,符合开闭原则

E为树形结构提供了一种灵活的解决方案,通过递归组合容器对象和叶子对象,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

缺点:

    使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联。

4、组合模式使用场景

组合模式使用场景:

    A当发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,应该考虑用组合模式。
    B基本对象可以被组合成更复杂的组合对象,而组合对象又可以被组合,客户代码中,任何用到基本对象的地方都可以使用组合对象。

二、 组合模式实现

Component抽象类:

#ifndef COMPONENT_H
#define COMPONENT_H
#include 
using namespace std;
 
//Component抽象基类,为组合中的对象声明接口,声明了类共有接口的缺省行为(add,remove,getChild函数),
//声明一个接口函数可以访问Component的子组件
class Component
{
public:
    //纯虚函数,只提供接口,没有默认的实现
    virtual void operation() = 0;
    // 虚函数,提供接口,默认的实现打印当前调用函数
    virtual void add(Component* com)
    {
        cout << "Component::add" << endl;
    }
    virtual void remove(Component* com)
    {
        cout << "Component::remove" << endl;
    }
    virtual Component* getChild(int index)
    {
        cout << "Component::getChild" << endl;
    }
protected:
    //只可以被子类调用,不对外开放
    Component(){}
};
 
#endif // COMPONENT_H


Leaf叶子节点类:

#ifndef LEAF_H
#define LEAF_H
#include "Component.h"
 
//Leaf是叶子结点,是不含有子组件的结点类,继承基类add、remove、getChild方法
class Leaf : public Component
{
public:
    Leaf(){}
    //需要实现基类的operation接口
    virtual void operation()
    {
        cout << "Leaf::operation" << endl;
    }
};
 
#endif // LEAF_H


Composite类:

#ifndef COMPOSITE_H
#define COMPOSITE_H
#include "Component.h"
#include 
 
//Composite:含有子组件的类
class Composite : public Component
{
public:
    //实现所有接口
    void operation()
    {
        cout << "Composite::operation" << endl;
        vector::iterator iter = this->m_comVec.begin();
        for(iter;iter!= this->m_comVec.end();iter++)
        {
            (*iter)->operation();
        }
    }
    void add(Component* com)
    {
        cout << "Composite::add an component" << endl;
        m_comVec.push_back(com);
    }
    void remove(Component* com)
    {
        cout << "Composite::remove an component" << endl;
        vector::iterator iter = this->m_comVec.begin();
        for(iter;iter!= this->m_comVec.end();iter++)
        {
            if(*iter == com)
                m_comVec.erase(iter);
        }
    }
    Component* getChild(int index)
    {
        if(index < 0 || index > this->m_comVec.size())
        {
            return NULL;
        }
        return this->m_comVec[index];
    }
private:
    //vector来保存子组件
    vector m_comVec;
};
 
#endif // COMPOSITE_H


客户调用程序:

#include "Composite.h"
#include "Leaf.h"
 
int main()
{
    //不管是叶子Leaf还是Composite对象pRoot、pCom都实现了operation接口,可以一致对待,
    //直接调用operation(),体现了“使得用户对单个对象和组合对象的使用具有一致性。”
    Composite* pRoot = new Composite();
    //组合对象添加叶子节点
    pRoot->add(new Leaf());
    Leaf* pLeaf1 = new Leaf();
    Leaf* pLeaf2 = new Leaf();
    //叶子节点只实现了operation方法,其他add、remove、getChild都继承自基类
    pLeaf1->add(pLeaf2);//执行基类add
    pLeaf1->remove(pLeaf2);//执行基类remove
    //执行叶子Operation操作
    pLeaf1->operation();
 
    //组合对象实现了基类Component的所有接口
    Composite* pCom = new Composite();
    //组合对象添加叶子节点
    pCom->add(pLeaf1);
    //组合对象添加叶子节点
    pCom->add(pLeaf2);
    //执行组合对象Operation操作
    pCom->operation();
    //组合对象添加组合对象
    pRoot->add(pCom);
    //执行组合对象Operation操作
    pRoot->operation();
 
    return 0;
}


三、组合模式实例

    一个集团公司,有一个母公司,下设很多家子公司。不管是母公司还是子公司,都有各自直属的财务部、人力资源部、销售部等。对于母公司来说,不论是子公司,还是直属的财务部、人力资源部,都是部门。整个公司的部门拓扑图就是一个树形结构。

设计模式(十二)——组合模式_第2张图片

Company公司抽象类:

#ifndef COMPANY_H
#define COMPANY_H
#include 
#include 
#include 
using namespace std;
 
//公司抽象类
class Company
{
public:
    Company(string name)
    {
        m_name = name;
    }
    //增加节点
    virtual void add(Company* com) = 0;
    //显示
    virtual void show(int depth) = 0;
    //删除节点
    virtual void remove(Company* com) = 0;
    //职责
    virtual void duty() = 0;
    bool operator==(const Company& com)
    {
        return m_name == com.m_name;
    }
protected:
    string m_name;
};
 
#endif // COMPANY_H


ConcreteCompany具体公司类:

#ifndef CONCRETECOMPANY_H
#define CONCRETECOMPANY_H
#include "Company.h"
#include 
 
//具体公司类
class ConcreteCompany : public Company
{
public:
    ConcreteCompany(string name):Company(name)
    {
        m_childs = new list;
    }
    ~ConcreteCompany()
    {
        for(list::iterator it = m_childs->begin(); it != m_childs->end(); it++)
            delete *it;
        delete m_childs;
    }
    //增加子节点
    void add(Company* com)
    {
        m_childs->push_back(com);
    }
    //删除子节点
    void remove(Company* com)
    {
        for(list::iterator it = m_childs->begin(); it != m_childs->end(); it++)
        {
            if(**it == *com)
            {
                m_childs->erase(it);
                break;
            }
        }
    }
    //显示本节点的子节点
    void show(int depth)
    {
        for(int i = 0;i < depth; i++)
            std::cout<<"-";
        //显示公司节点名称
        std::cout << m_name << std::endl;
        for(list::iterator it = m_childs->begin(); it != m_childs->end(); it++)
            (*it)->show(depth + 4);//显示本节点的子节点名称
    }
    //显示子节点的职责
    void duty()
    {
        for(list::iterator it = m_childs->begin(); it != m_childs->end(); it++)
            (*it)->duty();//显示本节点的子节点职责
    }
private:
    list* m_childs;
};
 
#endif // CONCRETECOMPANY_H


FinanceDepartment财务部门类:

#ifndef FINANCEDEPARTMENT_H
#define FINANCEDEPARTMENT_H
#include "Company.h"
using namespace std;
 
//公司财务部门
class FinanceDepartment: public Company
{
public:
    FinanceDepartment(string name):Company(name){}
    void add(Company* com)
    {
 
    }
    void remove(Company* com)
    {
 
    }
    //显示财务部门名称
    void show(int depth)
    {
        for(int i = 0;i < depth; i++)
            std::cout<<"-";
        std::cout << m_name << std::endl;
    }
    //显示财务部分职责
    void duty()
    {
        std::cout<< m_name <<"  Financial Management"< 
  


HRDepartment人力资源部门类:

#ifndef HRDEPARTMENT_H
#define HRDEPARTMENT_H
#include "Company.h"
 
class HRDepartment : public Company
{
public:
    HRDepartment(string name):Company(name){}
    //显示人力资源部分名称
    void show(int depth)
    {
        for(int i=0;i < depth;i++)
            std::cout<<"-";
        std::cout<< m_name < 
  


客户调用程序:

#include "Company.h"
#include "ConcreteCompany.h"
#include "FinanceDepartment.h"
#include "HRDepartment.h"
 
int main()
{
    //北京总公司
    Company* root = new ConcreteCompany("BeiJing Head Office");
    root->add(new HRDepartment("HRDepartment of Head Office"));
    root->add(new FinanceDepartment("FinanceDepartment of Head Office"));
 
    //华东上海分公司
    Company* ShangHaicomp=new ConcreteCompany("China East ShangHai Branch Office");
    ShangHaicomp->add(new HRDepartment("HRDepartment of ShangHai Branch Office"));
    ShangHaicomp->add(new FinanceDepartment("FinanceDepartment of ShangHai Branch Office"));
    //华东分公司隶属北京总公司
    root->add(ShangHaicomp);
    //华东分公司南京办事处
    Company* NanJingOffice=new ConcreteCompany("NanJing Office");
    NanJingOffice->add(new HRDepartment("HRDepartment of NanJing Office"));
    NanJingOffice->add(new FinanceDepartment("FinanceDepartment of NanJing Office"));
    //南京办事处隶属华东分公司
    ShangHaicomp->add(NanJingOffice);
 
    //西南成都分公司
    Company* ChengDucomp=new ConcreteCompany("China SouthWest ChengDu Branch Office");
    ChengDucomp->add(new HRDepartment("HRDepartment of ChengDu Branch Office"));
    ChengDucomp->add(new FinanceDepartment("FinanceDepartment of ChengDu Branch Office"));
    //西南分公司隶属北京总公司
    root->add(ChengDucomp);
 
    Company* KunMingOffice=new ConcreteCompany("KunMing Office");
    KunMingOffice->add(new HRDepartment("HRDepartment of KunMing Office"));
    KunMingOffice->add(new FinanceDepartment("FinanceDepartment of KunMing Office"));
    //昆明办事处隶属西南分公司
    ChengDucomp->add(KunMingOffice);
    //显示公司的树形结构
    std::cout<<"Structure:"<show(1);
    //显示公司所有部门的职责
    std::cout<duty();
    delete KunMingOffice,ChengDucomp;
    delete NanJingOffice,ShangHaicomp;
    delete root;
    return 0;
}