设计模式之十五:组合模式(Composite)

组合模式:
将对象组合成树形结构来表示部分与整体的关系。组合模式让客户能将单个对象和组合对象统一对待。
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

感觉这是一个很有意思的模式,递归的思路在这里面也得到了体现。如果考虑的业务模型中存在树形结构可以考虑这个模式。

UML图:

这里写图片描述

主要包括:

  1. Component(DrawingElement):为组合模式中的对象声明了一个接口;实现了一些缺省的行为;声明了一些访问子对象的接口。
  2. Leaf(PrimitiveElement):代表组合模式中的叶节点。叶节点不再包含其它节点。
  3. Composite(CompositeElement):定义有组合对象的行为;包含其它组合对象;实现了对子对象操作的一些接口。

C++代码实现如下:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Component
{
        public:
                Component(string n=string("")):name(n)
                {   

                }
                virtual void add(Component * c)
                {
                }
                virtual void removeComponent(Component * c)
                {

                }
                virtual Component* getChild(int index)
                {

                }
                virtual void display(int depth)=0;

        protected:
                string name;
};

class Leaf:public Component
{
    public:
            Leaf(string str=""):Component(str)
            {

            }
            void display(int depth)
            {
                string str(depth+2,'-');
                std::cout<<str<<name<<std::endl;
            }
};

class Composite:public Component
{
        public:
            Composite(string str=""):Component(str)
            {

            }
            void add(Component* c)
            {
                children.push_back(c);
            }
            void removeComponent(Component *c)
            {
                children.erase( remove(children.begin(),children.end(),c),children.end());
            }
            void display(int depth)
            {
                string str(depth+2,'-');
                std::cout<<str<<name<<std::endl;
                vector<Component*>::iterator iter=children.begin();
                for(;iter!=children.end();iter++)
                        (*iter)->display(depth+1);
            }

            Component* getChild(int index)
            {
                return children[index];
            }

        private:
            vector<Component *> children;

};


int main()
{
    std::cout<<"组合模式例子"<<std::endl;
    Component *root=new Composite("root");
    Component * etc=new Composite("etc");
    Component * mnt=new Composite("mnt");

    root->add(etc);
    root->add(mnt);

    Component * txt1=new Leaf("txt1");
    Component *txt2=new Leaf("txt2");
    etc->add(txt1);
    etc->add(txt2);

    root->display(0);

    std::cout<<std::endl<<std::endl<<"after erase"<<std::endl;
    etc->removeComponent(txt1);
    root->display(0);

    return 0;
}

这里也复习了一下stl容器删除操作。如果提供的是指针,直接进行erase即可,但是如果要删除具有特定值的对象,可以按照下列规则:


对于在内存中连续的顺序容器,如vector,deque,string推荐erase-remove的方法(这种方法对list也可用,但是list有更高效的方法)

vector<int> c;  
//注意remove是<algorithm>中的函数
c.erase( remove(c.begin(),c.end(), 25), c.end());

对于list而言,可以使用list的成员函数remove,这样效率会更高一些:

list<int> list_int;  
....  
list_int.remove(25);  

对于关联容器,可以直接调用erase函数

map<int, int> mapContainer;  
...  
mapContainer.erase(25); 

执行输出:

这里写图片描述

下面是一个具体的绘图程序的例子:

  1. Component为DrawingElement,为绘图元素
  2. Leaf为PrimitiveElement,基本的绘图元素,不能再包含其它绘图元素
  3. Composite为CompositeElement

实际上上面的结构是UI中各种元素的简化版,UI中存在各种基本元素,比如按钮,文本框,也包括组合元素,比如各种布局控件,对话框等。它们应该是组合模式一个很好的应用。

UML类图:

这里写图片描述

C++实现代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class DarawingElement
{
        public:
                DarawingElement(string n=string("")):name(n)
                {   

                }
                virtual void add(DarawingElement * c)
                {
                }
                virtual void removeDarawingElement(DarawingElement * c)
                {

                }
                virtual DarawingElement* getChild(int index)
                {

                }
                virtual void display(int depth)=0;

        protected:
                string name;
};

class PrimitiveElement:public DarawingElement
{
    public:
            PrimitiveElement(string str=""):DarawingElement(str)
            {

            }
            void display(int depth)
            {
                string str(depth+2,'-');
                std::cout<<str<<name<<std::endl;
            }
};

class CompositeElement:public DarawingElement
{
        public:
            CompositeElement(string str=""):DarawingElement(str)
            {

            }
            void add(DarawingElement* c)
            {
                children.push_back(c);
            }
            void removeElement(DarawingElement *c)
            {
                children.erase( remove(children.begin(),children.end(),c),children.end());
            }
            void display(int depth)
            {
                string str(depth+2,'-');
                std::cout<<str<<"+"<<name<<std::endl;
                vector<DarawingElement*>::iterator iter=children.begin();
                for(;iter!=children.end();iter++)
                        (*iter)->display(depth+1);
            }

        private:
            vector<DarawingElement *> children;

};


int main()
{
    std::cout<<"具体的组合模式,画图程序例子"<<std::endl;
    DarawingElement *pic=new CompositeElement("picture");
    DarawingElement * redLine=new PrimitiveElement("red line");
    DarawingElement * blueCircle=new PrimitiveElement("blueCircle");
    DarawingElement * greenBox=new PrimitiveElement("green box");

    pic->add(redLine);
    pic->add(blueCircle);
    pic->add(greenBox);

    DarawingElement * twoCircles=new CompositeElement("two circles");
    DarawingElement * blackCircle=new PrimitiveElement("black circle");
    DarawingElement * whiteCircle=new PrimitiveElement("white Circle");

    twoCircles->add(blackCircle);
    twoCircles->add(whiteCircle);
    pic->add(twoCircles);
    pic->display(1);


    return 0;
}

执行输出:

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值