设计模式-结构型模式-组合模式

工程源码:

c++设计模式-结构型模式-组合模式icon-default.png?t=M4ADhttps://download.csdn.net/download/qq_40788199/85665241码云:

设计模式-结构型模式-组合模式icon-default.png?t=M4ADhttps://gitee.com/gongguixing/c-design-mode.git

1、组合模式的定义与特点

组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式

组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下。

 由上图可以看出,其实根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让它们具备一致行为。

这样,在组合模式中,整个树形结构中的对象都属于同一种类型,带来的好处就是用户不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给用户的使用带来极大的便利。

组合模式的主要优点有:

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;


其主要缺点是:

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
  2. 不容易限制容器中的构件;
  3. 不容易用继承的方法来增加构件的新功能;

 2、组合模式的结构与实现

1. 模式的结构

组合模式包含以下主要角色。

  1. 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
  2. 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
  3. 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。


组合模式分为透明式的组合模式和安全式的组合模式。

3、分类

3.1、透明方式

在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。其结构图如图 1 所示。

 3.2、安全方式

在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。其结构图如图 2 所示。

 4、代码实现

假如要访问集合 c0={leaf1,{leaf2,leaf3}} 中的元素,其对应的树状图如图 3 所示。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== 编辑

4.2透明组合模式 

抽象构件(Component)角色

#ifndef ICOMPONENT_H
#define ICOMPONENT_H

#include <string>
using namespace std;

// 透明方式
// 抽象构件角色
// 抽象构件(Component)角色:
// 它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。
class IComponent
{
public:
    virtual ~IComponent() {}

    // 添加子对象
    virtual void add(IComponent *c)     = 0;

    // 删除子对象
    virtual void remove(IComponent *c)  = 0;

    // 获取指定子对象
    virtual IComponent* getChild(uint8_t i) = 0;

    // 方法调用
    virtual void operation()            = 0;

    // 释放所有子对象
    virtual void deleteChild()          = 0;

    // 获取唯一标识属性
    virtual string &getKey()            = 0;

    // 获取节点类型
    virtual string &getType()           = 0;
};

#endif // ICOMPONENT_H

树叶构件(Leaf)角色 

#ifndef LEAF_H
#define LEAF_H

#include "icomponent.h"

// 透明方式
// 树叶构件角色
// 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
class Leaf : public IComponent
{
public:
    Leaf(const string &key);

    void add(IComponent *c)     override;

    void remove(IComponent *c)  override;

    IComponent* getChild(uint8_t i)override;

    void deleteChild()          override;

    void operation()            override;

    string &getKey()            override;

    string &getType()           override;

private:
    string mKey;
    string mType;
};

#endif // LEAF_H
#include "leaf.h"
#include <iostream>

Leaf::Leaf(const string &key)
    : mKey(key)
{
    mType = "Leaf";
}

void Leaf::add(IComponent *c)
{
}

void Leaf::remove(IComponent *c)
{

}

IComponent *Leaf::getChild(uint8_t i)
{
    return NULL;
}

void Leaf::deleteChild()
{

}

void Leaf::operation()
{
    std::cout << "Leaf: " << mKey << " operation." << std::endl;
}

string &Leaf::getKey()
{
    return mKey;
}

string &Leaf::getType()
{
    return mType;
}

 树枝构件(Composite)角色 / 中间构件

#ifndef COMPOSITE_H
#define COMPOSITE_H

#include "icomponent.h"
#include <vector>

// 透明方式
// 树枝构件角色 / 中间构件
// 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。
// 它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
class Composite : public IComponent
{
public:
    Composite(const string &key);

    void add(IComponent *c)     override;

    void remove(IComponent *c)  override;

    IComponent* getChild(uint8_t i)override;

    void deleteChild()          override;

    void operation()            override;

    string &getKey()            override;

    string &getType()           override;

private:
    // 子对象容器
    vector<IComponent*> mChildren;
    // 唯一标识属性
    string mKey;
    // 节点类型
    string mType;
};

#endif // COMPOSITE_H
#include "composite.h"
#include <iostream>

Composite::Composite(const string &key)
    : mKey(key)
{
    mType = "Composite";
}

void Composite::add(IComponent *c)
{
    mChildren.push_back(c);
    std::cout << "Composite: " << mKey << " add ";
    std::cout << c->getType() << ": " << c->getKey() << std::endl;
}

void Composite::remove(IComponent *c)
{
    uint8_t i = 0;
    for (IComponent *p : mChildren)
    {
        // 地址一致则删除
        if (p == c)
        {
            mChildren.erase(mChildren.begin() + i);
            std::cout << "Composite: " << mKey << " remove ";
            std::cout << c->getType() << ": " << c->getKey() << std::endl;
            break;
        }
        i++;
    }
}

IComponent *Composite::getChild(uint8_t i)
{
    if (i <= mChildren.size())
    {
        return mChildren.at(i);
    }

    return NULL;
}

void Composite::deleteChild()
{
    for (IComponent *p : mChildren)
    {
        std::cout << "Composite: " << mKey << " delete ";
        std::cout << p->getType() << ": " << p->getKey() << std::endl;

        // 树枝构件则释放子构件
        if (p->getType().compare("Composite") == 0)
        {
            p->deleteChild();
            delete p;
        }
        // 叶子构件直接释放
        else if (p->getType().compare("Leef") == 0)
        {
            delete p;
        }
    }

    mChildren.clear();
}

void Composite::operation()
{
    for (IComponent *p : mChildren)
    {
        if (p)
        {
            p->operation();
        }
    }
}

string &Composite::getKey()
{
    return mKey;
}

string &Composite::getType()
{
    return mType;
}

 调用示例

#include <iostream>
#include "leaf.h"
#include "composite.h"

#include "sleaf.h"
#include "scomposite.h"

int main()
{
    // 透明方式调用
    // 创建树枝构件
    IComponent *c0 = new Composite("c0");
    IComponent *c1 = new Composite("c1");
    // 创建叶子构件
    IComponent *leaf1 = new Leaf("leaf1");
    IComponent *leaf2 = new Leaf("leaf2");
    IComponent *leaf3 = new Leaf("leaf3");
    // c0添加叶子leaf1
    c0->add(leaf1);
    // c0添加树枝c1
    c0->add(c1);
    // c1添加叶子leaf2
    c1->add(leaf2);
    // c1添加叶子leaf3
    c1->add(leaf3);
    // c0方法调用
    c0->operation();
    // 释放所有子节点
    c0->deleteChild();

    return 0;
}

4.2、安全组合模式

安全式的组合模式与透明式组合模式的实现代码类似,只要对其做简单修改就可以了,代码如下。

抽象构件(Component)角色 

#ifndef ISCOMPONENT_H
#define ISCOMPONENT_H

#include <string>
using namespace std;

// 透明方式
// 抽象构件角色
// 抽象构件(Component)角色:
// 它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。
// 在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成
class ISComponent
{
public:
    virtual ~ISComponent() {}

    // 方法调用
    virtual void operation()            = 0;

    // 获取唯一标识属性
    virtual string &getKey()            = 0;

    // 获取节点类型
    virtual string &getType()           = 0;
};

树叶构件(Leaf)角色:

#ifndef SLEAF_H
#define SLEAF_H

#include "iscomponent.h"

// 安全方式
// 树叶构件角色
// 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
class SLeaf : public ISComponent
{
public:
    SLeaf(const string &key);

    void operation()            override;

    string &getKey()            override;

    string &getType()           override;

private:
    string mKey;
    string mType;
};

#endif // SLEAF_H
#include "sleaf.h"
#include <iostream>

SLeaf::SLeaf(const string &key)
    : mKey(key)
{
    mType = "SLeaf";
}

void SLeaf::operation()
{
    std::cout << "SLeaf: " << mKey << " operation." << std::endl;
}

string &SLeaf::getKey()
{
    return mKey;
}

string &SLeaf::getType()
{
    return mType;
}

 树枝构件(Composite)角色 / 中间构件

 

#ifndef SCOMPOSITE_H
#define SCOMPOSITE_H

#include "iscomponent.h"
#include <vector>

// 安全方式
// 树枝构件角色 / 中间构件
// 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。
// 它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
class SComposite : public ISComponent
{
public:
    SComposite(const string &key);

    void add(ISComponent * p);

    void remove(ISComponent *c) ;

    ISComponent* getChild(uint8_t i);

    void deleteChild();

    void operation()            override;

    string &getKey()            override;

    string &getType()           override;

private:
    vector<ISComponent*> mChildren;
    string mKey;
    string mType;
};

#endif // SCOMPOSITE_H
#include "scomposite.h"
#include <iostream>

SComposite::SComposite(const string &key)
    : mKey(key)
{
    mType = "SComposite";
}

void SComposite::add(ISComponent *p)
{
    mChildren.push_back(p);
    std::cout << "SComposite: " << mKey << " add ";
    std::cout << p->getType() << ": " << p->getKey() << std::endl;
}

void SComposite::remove(ISComponent *c)
{
    uint8_t i = 0;
    for (ISComponent *p : mChildren)
    {
        if (p == c)
        {
            mChildren.erase(mChildren.begin() + i);
            std::cout << "Composite: " << mKey << " remove ";
            std::cout << c->getType() << ": " << c->getKey() << std::endl;
            break;
        }
        i++;
    }
}

ISComponent *SComposite::getChild(uint8_t i)
{
    if (i <= mChildren.size())
    {
        return mChildren.at(i);
    }

    return NULL;
}

void SComposite::deleteChild()
{
    for (ISComponent *p : mChildren)
    {
        std::cout << "SComposite: " << mKey << " delete ";
        std::cout << p->getType() << ": " << p->getKey() << std::endl;

        if (p->getType().compare("SComposite") == 0)
        {
            SComposite * s = (SComposite*)p;
            if (s)
            {
                s->deleteChild();
            }
            delete p;
        }
        else if (p->getType().compare("SLeef") == 0)
        {
            delete p;
        }
    }

    mChildren.clear();
}

void SComposite::operation()
{
    for (ISComponent *p : mChildren)
    {
        if (p)
        {
            p->operation();
        }
    }
}

string &SComposite::getKey()
{
    return mKey;
}

string &SComposite::getType()
{
    return mType;
}

 调用示例

#include <iostream>
#include "leaf.h"
#include "composite.h"

#include "sleaf.h"
#include "scomposite.h"

int main()
{
    // 安全方式调用
    // 创建树枝构件
    SComposite *sc0 = new SComposite("sc0");
    SComposite *sc1  = new SComposite("sc1");
    // 创建叶子构件
    ISComponent *sleaf1 = new SLeaf("sleaf1");
    ISComponent *sleaf2 = new SLeaf("sleaf2");
    ISComponent *sleaf3 = new SLeaf("sleaf3");
    // sc0添加叶子sleaf1
    sc0->add(sleaf1);
    // sc0添加树枝sc1
    sc0->add(sc1);
    // sc1添加叶子sleaf2
    sc1->add(sleaf2);
    // sc1添加叶子sleaf3
    sc1->add(sleaf3);
    // sc0方法调用
    sc0->operation();
    // 释放所有子节点
    sc0->deleteChild();

    return 0;
}

 

组合模式的应用场景

前面分析了组合模式的结构与特点,下面分析它适用的以下应用场景。

  1. 在需要表示一个对象整体与部分的层次结构的场合。
  2. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值