组合模式

组合模式,是(构造型)结构型的设计模式之一。通过递归手段来构造树形的对象结构,并可以通过一个对象来访问整个对象树。
角色及职责
这里写图片描述
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值