组合模式

来源:互联网 发布:淘宝日本直邮物流信息 编辑:程序博客网 时间:2024/04/29 05:45

组合模式

  • 组合模式
    • 概念
    • 角色及职责
    • 案例

概念

组合模式,是(构造型)结构型的设计模式之一。通过递归手段来构造树形的对象结构,并可以通过一个对象来访问整个对象树。

角色及职责

这里写图片描述

  • Component (树形结构的节点抽象)

    • 为所有的对象定义统一的接口(公共属性,行为等的定义)
    • 提供管理子节点对象的接口
    • [可选]提供管理父节点对象的接口
  • Leaf (树形结构的叶节点)
    Component的实现子类–普通文件

  • Composite(树形结构的枝节点)
    Component的实现子类–子目录

适用于:
单个对象和组合对象的使用具有一致性。将对象组合成树形结构以表示“部分–整体”

案例

#include <iostream>#include <list>using namespace std;/**树形结构--共同接口--整体和部分* 文件夹--普通文件--文件夹(三个中任意两个或三个类型的组合)* 文件夹下又有文件夹和普通文件(典型的树形结构)*//*抽象类--子树或者叶子节点均继承自他*/class IFile{public:    virtual void display()=0;    virtual int add(IFile *file) = 0;    virtual int remove(IFile* file) = 0;    virtual list<IFile *> *getChild()=0;    string getName()    {        return m_name;    }public :    string m_name;//子树(子文件夹)或者叶子节点(普通文件)的名字    int cnt;//记录当前对象的下一级对象(目录或文件)前面应该有的分隔符("--")数量            //--表示第几层子目录            //分隔符("--")数量表示当前目录相对根目录来说是第几层子目录};/*叶子节点--普通文件*/class File : public IFile{public:    File(string name)//构造函数    {        m_name =  name;        cnt = 0;    }    virtual void display()//普通文件的显示函数--直接显示名字    {        cout<<m_name<<endl;    }    /*不具备插入孩子属性--返回-1*/    virtual int add(IFile *file)    {        return -1;    }     /*不具备删除孩子属性--返回-1*/    virtual int remove(IFile* file)    {            return -1;    }     /*不具备获取孩子属性--返回-1*/    virtual list<IFile *>*getChild()    {            return NULL;    }};/*子树部分--目录将目录和普通文件组合--组合模式构成文件系统的树形图*/class Dir : public IFile{private:    list<IFile*> * m_list;public:    Dir(string name)    {        m_name =  name;        m_list = new list<IFile *>;//为孩子起始位置分配空间--建立一个链表        m_list->clear();//链表清空        cnt = 0;//表示当前目录就是根目录--根目录的0级子目录    }    /*对于目录的显示函数--需要递归显示子目录*/    virtual void display()    {        /*1.获取当前目录孩子的起始位置--m_list*/        list<IFile*> *chil_list = getChild();        /*2.显示当前目录的名字*/        cout<<m_name<<endl;        /*3.如果孩子非空表示该目录有子目录或者文件        *如果为空表示是空文件夹,什么也不做--退出显示函数不进行递归        * --递归结束的条件--孩子为空(空目录或者普通文件都会结束递归)        */        if(chil_list != NULL && !chil_list->empty())        {            this->cnt++;//3.1 当前目录有子目录或者文件--前面的分隔符数量加1            /*3.2 遍历当前目录的孩子--当前目录的文件或者子目录*/            for( list<IFile*>::iterator it = chil_list->begin();it != chil_list->end();it++)            {                for(int i = 0;i < this->cnt;i++)//3.3 根据cnt打印分隔符--层级越深,cnt越大--                                                //每一级目录的cnt表示他的下一级文件或者子目录相对于根目录(调用display函数的对象)的层级关系                    cout<<"--";                (*it)->cnt =  this->cnt;//3.4 将当前目录的cnt传承给下一级的文件或者子目录--                                        //--下一级文件或者目录前面的分隔符是在上一级的基础上递增的                (*it)->display();//3.5 递归显示每一个孩子节点            }        }        /*4. 在显示结束以后要将根目录(调用display函数的对象)的层级关系清零        --否则再次调用的时候会在上一次的基础上累加分隔符数量*/        cnt = 0;    }    /*向目录添加孩子--子目录或者文件*/    virtual int add(IFile *file)    {        m_list->push_back(file);//将孩子插入链表        return 0;    }    /*从目录删除孩子--从链表移除一个孩子节点*/    virtual int remove(IFile* file)    {        m_list->remove(file);        return 0;    }    /*获取孩子的起始位置*/    virtual list<IFile *>*getChild()    {        return m_list;    }};/*测试案例*/int main(){    Dir * root = new Dir("C");//根目录    root->display();    Dir * dir1 = new Dir("folder1");//子目录1    File * file1 = new File("a.txt");//文件1    root->add(dir1);    root->add(file1);    root->display();    Dir * dir2 = new Dir("folder2");//子目录2    File * file2 = new File("b.txt");//文件2    dir1->add(dir2);//子目录2添加到子目录1    dir2->add(file2);//文件2添加到子目录2    dir1->add(file2);//文件2添加到子目录1    root->add(file2);//文件2添加到根目录    root->display();//显示根目录的文件系统结构    return 0;}
0 0