首页 > 编程语言 >c/c++设计模式--组合模式

c/c++设计模式--组合模式

时间:2024-05-31 18:32:33浏览次数:27  
标签:-- c++ nmsp2 Add pdir1 File FileSystem new 设计模式

 

 

namespace _nmsp1
{    
    //文件相关类
    class File
    {
    public:
        //构造函数
        File(string name) :m_sname(name) {}

        //显示文件名
        void ShowName(string lvlstr) //lvlstr:为了显示层次关系的缩进字符串内容
        {
            cout << lvlstr << "-" << m_sname << endl; //显示“-”代表是一个文件,属末端节点(不会再有子节点)
        }

    private:
        string m_sname; //文件名
    };

    //目录相关类
    class Dir
    {
    public:
        Dir(string name) :m_sname(name) {}

    public:
        //目录中可以增加其他文件
        void AddFile(File* pfile)
        {
            m_childFile.push_back(pfile);
        }
        //目录中可以增加其他目录
        void AddDir(Dir* pdir)
        {
            m_childDir.push_back(pdir);
        }

        //显示目录名,同时也要负责其下面的文件和目录名的显示工作
        void ShowName(string lvlstr)//lvlstr:为了显示层次关系的缩进字符串内容
        {
            //(1)输出本目录名
            cout << :q << "+" << m_sname << endl; //显示“+”代表是一个目录,其中会包含其他内容

            //(2)输出所包含的文件名
            lvlstr += "    "; //本目录中的文件和目录的显示,要缩进一些来显示
            for (auto iter = m_childFile.begin(); iter != m_childFile.end(); ++iter)
            {
                (*iter)->ShowName(lvlstr); //显示文件名
            }

            //(3)输出所包含的目录名
            for (auto iter = m_childDir.begin(); iter != m_childDir.end(); ++iter)
            {
                (*iter)->ShowName(lvlstr); //显示目录名,这里涉及了递归调用 
            }
        }

    private:
        string m_sname; //目录名
        list<File*> m_childFile; //目录中包含的文件列表
        list<Dir*> m_childDir; //目录中包含的子目录列表
    };

}

int main()
{

/*
    //(1)创建各种目录,文件对象
    _nmsp1::Dir *pdir1 = new _nmsp1::Dir("root");
    //----
    _nmsp1::File* pfile1 = new  _nmsp1::File("common.mk");
    _nmsp1::File* pfile2 = new  _nmsp1::File("config.mk");
    _nmsp1::File* pfile3 = new  _nmsp1::File("makefile");
    //-----
    _nmsp1::Dir* pdir2 = new _nmsp1::Dir("app");
    _nmsp1::File* pfile4 = new  _nmsp1::File("nginx.c");
    _nmsp1::File* pfile5 = new  _nmsp1::File("ngx_conf.c");
    //-----
    _nmsp1::Dir* pdir3 = new _nmsp1::Dir("signal");
    _nmsp1::File* pfile6 = new  _nmsp1::File("ngx_signal.c");
    //-----
    _nmsp1::Dir* pdir4 = new _nmsp1::Dir("_include");
    _nmsp1::File* pfile7 = new  _nmsp1::File("ngx_func.h");
    _nmsp1::File* pfile8 = new  _nmsp1::File("ngx_signal.h");

    //(2)构造树形目录结构
    pdir1->AddFile(pfile1);
    pdir1->AddFile(pfile2);
    pdir1->AddFile(pfile3);
    //----
    pdir1->AddDir(pdir2);
        pdir2->AddFile(pfile4);
        pdir2->AddFile(pfile5);
    //----
    pdir1->AddDir(pdir3);
        pdir3->AddFile(pfile6);
    //----
    pdir1->AddDir(pdir4);
        pdir4->AddFile(pfile7);
        pdir4->AddFile(pfile8);


    //(3)输出整个目录结构,只要通过根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录显示。
    pdir1->ShowName(""); //缩进字符刚开始可以为空
    //pdir2->ShowName("");

    //(4)释放资源
    delete pfile8;
    delete pfile7;
    delete pdir4;
    //----
    delete pfile6;
    delete pdir3;
    //----
    delete pfile5;
    delete pfile4;
    delete pdir2;
    //----
    delete pfile3;
    delete pfile2;
    delete pfile1;
    delete pdir1;
    */

}

使用组合模式

namespace _nmsp2
{
    //抽象父类FileSystem(抽象接口)
    class FileSystem
    {
    public:
        virtual void ShowName(int level) = 0; //显示名字,参数level用于表示显示的层次,用于显示对齐
        virtual int Add(FileSystem* pfilesys) = 0; //向当前目录中增加文件或者子目录
        virtual int Remove(FileSystem* pfilesys) = 0; //从当前目录中移除文件或者子目录
        
        virtual ~FileSystem() {}   //做父类时析构函数应该为虚函数
    };

    //文件相关类
    class File :public FileSystem
    {
    public:
        //构造函数
        File(string name) :m_sname(name) {}
        //显示名
        virtual void ShowName(int level)
        {
            for (int i = 0; i < level; ++i)
            {
                cout << "    "; //显示若干个空格用于对齐
            }
            cout << "-" << m_sname << endl;
        }
        virtual int Add(FileSystem* pfilesys)
        {
            return -1;
        }
        virtual int Remove(FileSystem* pfilesys)
        {
            return -1;
        }

    private:
        string m_sname; //文件名
    };

    //目录相关类
    class Dir :public FileSystem
    {
    public:
        //构造函数
        Dir(string name) :m_sname(name) {}

        //显示名字
        virtual void ShowName(int level)
        {
            //(1)显示若干个空格用于对齐
            for (int i = 0; i < level; ++i) { cout << "    "; }
            //(2)输出本目录名
            cout << "+" << m_sname << endl;
            //(3)显示的层级向下走一级
            level++;
            //(4)输出所包含的子内容(可能是文件,也可能是目录)
            //遍历目录中的文件和子目录
            for (auto iter = m_child.begin(); iter != m_child.end(); ++iter)
            {
                (*iter)->ShowName(level);
            }
        }

        virtual int Add(FileSystem* pfilesys)
        {
            m_child.push_back(pfilesys);
            return 0;
        }

        virtual int Remove(FileSystem* pfilesys)
        {
            m_child.remove(pfilesys);
            return 0;
        }

    private:
        string m_sname; //文件名
        list<FileSystem*> m_child; //目录中包含的文件或者其他目录列表
    };
}

int main()
{
  //(1)创建各种目录,文件对象
    _nmsp2::FileSystem* pdir1 = new _nmsp2::Dir("root");
    //----
    _nmsp2::FileSystem* pfile1 = new  _nmsp2::File("common.mk");
    _nmsp2::FileSystem* pfile2 = new  _nmsp2::File("config.mk");
    _nmsp2::FileSystem* pfile3 = new  _nmsp2::File("makefile");
    //-----
    _nmsp2::FileSystem* pdir2 = new _nmsp2::Dir("app");
    _nmsp2::FileSystem* pfile4 = new  _nmsp2::File("nginx.c");
    _nmsp2::FileSystem* pfile5 = new  _nmsp2::File("ngx_conf.c");
    //-----
    _nmsp2::FileSystem* pdir3 = new _nmsp2::Dir("signal");
    _nmsp2::FileSystem* pfile6 = new  _nmsp2::File("ngx_signal.c");
    //-----
    _nmsp2::FileSystem* pdir4 = new _nmsp2::Dir("_include");
    _nmsp2::FileSystem* pfile7 = new  _nmsp2::File("ngx_func.h");
    _nmsp2::FileSystem* pfile8 = new  _nmsp2::File("ngx_signal.h");

    //(2)构造树形目录结构
    pdir1->Add(pfile1);
    pdir1->Add(pfile2);
    pdir1->Add(pfile3);
    //----
    pdir1->Add(pdir2);
    pdir2->Add(pfile4);
    pdir2->Add(pfile5);
    //----
    pdir1->Add(pdir3);
    pdir3->Add(pfile6);
    //----
    pdir1->Add(pdir4);
    pdir4->Add(pfile7);
    pdir4->Add(pfile8);


    //(3)输出整个目录结构,只要通过根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录显示。
    pdir1->ShowName(0); //缩进字符刚开始可以为空
    //pdir2->ShowName("");

    //(4)释放资源
    delete pfile8;
    delete pfile7;
    delete pdir4;
    //----
    delete pfile6;
    delete pdir3;
    //----
    delete pfile5;
    delete pfile4;
    delete pdir2;
    //----
    delete pfile3;
    delete pfile2;
    delete pfile1;
    delete pdir1;

    return 0;

}

 

 

namespace _nmsp3
{
    class Dir;
    //抽象父类FileSystem(抽象接口)
    class FileSystem
    {
    public:
        virtual void ShowName(int level) = 0; //显示名字,参数level用于表示显示的层次,用于显示对齐

        virtual int countNumOfFiles() = 0; //统计目录下包含的文件个数
        
        virtual Dir* ifCompositeObj() { return nullptr; } //判断是否是一个树枝(组合对象)
        virtual ~FileSystem() {} //做父类时析构函数应该为虚函数
    };

    //文件相关类
    class File :public FileSystem
    {
    public:
        //构造函数
        File(string name) :m_sname(name) {}
        //显示名
        virtual void ShowName(int level)
        {
            for (int i = 0; i < level; ++i)
            {
                cout << "    "; //显示若干个空格用于对齐
            }
            cout << "-" << m_sname << endl;
        }        

        virtual int countNumOfFiles()//统计目录下包含的文件个数
        {
            return 1; //文件节点,做数量统计时按1计算
        }

    private:
        string m_sname; //文件名
    };

    //目录相关类
    class Dir :public FileSystem
    {
    public:
        //构造函数
        Dir(string name) :m_sname(name) {}

        //显示名字
        virtual void ShowName(int level)
        {
            //(1)显示若干个空格用于对齐
            for (int i = 0; i < level; ++i) { cout << "    "; }
            //(2)输出本目录名
            cout << "+" << m_sname << endl;
            //(3)显示的层级向下走一级
            level++;
            //(4)输出所包含的子内容(可能是文件,也可能是目录)
            //遍历目录中的文件和子目录
            for (auto iter = m_child.begin(); iter != m_child.end(); ++iter)
            {
                (*iter)->ShowName(level);
            }
        }

        int Add(FileSystem* pfilesys)
        {
            m_child.push_back(pfilesys);
            return 0;
        }

        int Remove(FileSystem* pfilesys)
        {
            m_child.remove(pfilesys);
            return 0;
        }

        virtual Dir* ifCompositeObj() { return this; }

        virtual int countNumOfFiles()//统计目录下包含的文件个数
        {
            int iNumOfFiles = 0;
            for (auto iter = m_child.begin(); iter != m_child.end(); ++iter)
            {
                iNumOfFiles += (*iter)->countNumOfFiles(); //递归调用
            }
            return iNumOfFiles;
        }

    private:
        string m_sname; //文件名
        list<FileSystem*> m_child; //目录中包含的文件或者其他目录列表
    };
}

int main()
{

/(1)创建各种目录,文件对象
    _nmsp3::Dir* pdir1 = new _nmsp3::Dir("root");
    //----
    _nmsp3::FileSystem* pfile1 = new  _nmsp3::File("common.mk");
    _nmsp3::FileSystem* pfile2 = new  _nmsp3::File("config.mk");
    _nmsp3::FileSystem* pfile3 = new  _nmsp3::File("makefile");
    //-----
    _nmsp3::Dir* pdir2 = new _nmsp3::Dir("app");
    _nmsp3::FileSystem* pfile4 = new  _nmsp3::File("nginx.c");
    _nmsp3::FileSystem* pfile5 = new  _nmsp3::File("ngx_conf.c");
    //-----
    _nmsp3::Dir* pdir3 = new _nmsp3::Dir("signal");
    _nmsp3::FileSystem* pfile6 = new  _nmsp3::File("ngx_signal.c");
    //-----
    _nmsp3::Dir* pdir4 = new _nmsp3::Dir("_include");
    _nmsp3::FileSystem* pfile7 = new  _nmsp3::File("ngx_func.h");
    _nmsp3::FileSystem* pfile8 = new  _nmsp3::File("ngx_signal.h");

    //(2)构造树形目录结构
    if (pdir2->ifCompositeObj() != nullptr)
    {
        //是个组合对象,可以向其中增加单个对象和其他组合对象。
        //.....
    }
    if (dynamic_cast<_nmsp3::Dir*>(pdir2) != nullptr)
    {
        //是个组合对象,可以向其中增加单个对象和其他组合对象。
        //.....

    }
    pdir1->Add(pfile1);
    //pfile1->Add(pfile2);不可以向单个对象中加入其他对象
    pdir1->Add(pfile2);
    pdir1->Add(pfile3);
    //----
    pdir1->Add(pdir2);
    pdir2->Add(pfile4);
    pdir2->Add(pfile5);
    //----
    pdir1->Add(pdir3);
    pdir3->Add(pfile6);
    //----
    pdir1->Add(pdir4);
    pdir4->Add(pfile7);
    pdir4->Add(pfile8);


    //(3)输出整个目录结构,只要通过根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录显示。
    pdir1->ShowName(0); //缩进字符刚开始可以为空
    //pdir2->ShowName("");

    cout << "文件的数量为:" << pdir1->countNumOfFiles() << endl;

    //(4)释放资源
    delete pfile8;
    delete pfile7;
    delete pdir4;
    //----
    delete pfile6;
    delete pdir3;
    //----
    delete pfile5;
    delete pfile4;
    delete pdir2;
    //----
    delete pfile3;
    delete pfile2;
    delete pfile1;
    delete pdir1;

    return 0;

}

 

    组合(Composite)模式:结构型模式,用来处理树形结构的数据     //(1)一个基本的目录内容遍历范例:用来表达和处理树形结构数据     //(2)使用组合模式改造目录内容遍历范例     //(3)引入组合(Composite)模式:TreeCtrl,TreeView     //定义:将一组对象(文件和目录)组织成树形结构以表示“部分-整体”的层次结构(目录中包含文件和子目录)。使得用户对单个对象(文件)        //和组合对象(目录)的操作/使用/处理(递归遍历并执行ShowName的逻辑)具有一致性。     //发挥作用的前提:具体数据必须能以树形结构的方式表示,树中包含了单个和组合对象。该模式专注于树形结构中单个对象和组合对象的递归遍历         //并且能把相同的操作(FileSystem定义的接口)应用在单个以及组合对象上并且可以忽略单个对象和组合对象之间的差别。     //3种角色:     //a)Component(抽象组件):FileSystem类。     //b)Leaf(叶子组件):File类。 KillVirus  --ExeFile, ImgFile类     //c)Composite(树枝组件):Dir类。     //Frame,Panel---文本,线,矩形,按钮,菜单,滚动
    //优点:a)简化代码书写。b)符合开闭原则。c)处理复杂的树形结构。
    //(4)透明组合模式与安全组合模式     //透明组合模式:在抽象组件(FileSystem类)中声明了所有用于管理和访问子节点的成员函数的实现手段。     //安全组合模式:抽象组件中用于管理和访问子节点的成员函数被转义到了树枝组件中。
    //(5)其他使用组合模式的场景探讨     //a)公司组织结构     //b)杀毒:exe .com ---pdir->KillVirus();     //c)利用图元进行图形的绘制工作

 

使用C++实现组合模式时,可以考虑一个简单的文件系统结构作为例子。在这个例子中,我们可以定义一个抽象基类 Component 代表文件系统中的文件和文件夹,然后派生出 Leaf 类表示文件,以及 Composite 类表示文件夹。

以下是一个简化的示例代码:

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

// 抽象基类 Component
class Component {
public:
    virtual void display() = 0;
    virtual ~Component() {}
};

// Leaf 类表示文件
class File : public Component {
private:
    std::string name;

public:
    File(const std::string& name) : name(name) {}
    void display() override {
        std::cout << "File: " << name << std::endl;
    }
};

// Composite 类表示文件夹
class Folder : public Component {
private:
    std::string name;
    std::vector<Component*> children;

public:
    Folder(const std::string& name) : name(name) {}
    void add(Component* component) {
        children.push_back(component);
    }
    void display() override {
        std::cout << "Folder: " << name << std::endl;
        for (Component* child : children) {
            child->display();
        }
    }
};

int main() {
    // 创建文件和文件夹
    File file1("file1.txt");
    File file2("file2.txt");
    Folder folder1("Folder1");
    folder1.add(&file1);
    folder1.add(&file2);

    File file3("file3.txt");
    Folder folder2("Folder2");
    folder2.add(&file3);
    folder2.add(&folder1);

    // 显示文件系统结构
    folder2.display();

    return 0;
}

在上面的示例中,我们定义了抽象基类 Component,并创建了 File 和 Folder 两种具体的子类。通过组合的方式,我们可以轻松地构建出文件和文件夹的层次结构,并且调用 display 方法可以统一地展示文件系统中的所有内容,即使它们是文件还是文件夹。这就展示了组合模式的灵活性和一致性。

 

想象你有一个树形结构,树的每个节点都可以有子节点,也可以没有。这个树可以表示不同层级的组织结构,比如公司的部门结构。

在组合模式中,树的节点被抽象为统一的对象,无论是叶子节点(没有子节点的节点)还是组合节点(有子节点的节点)。这样,你就可以统一地处理树的节点,而不需要知道它是叶子节点还是组合节点。

举个例子,假设你有一个组织结构的树,根节点代表公司,它有多个子节点代表不同的部门,每个部门又可以有自己的子部门,最后的叶子节点代表员工。现在,如果你想要计算公司的总人数,你可以使用组合模式。

以下是一个简单的C++例子:

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

// 抽象的组织结构节点
class OrganizationComponent {
public:
    virtual int getEmployeeCount() = 0;
    virtual ~OrganizationComponent() {}
};

// 叶子节点:员工
class Employee : public OrganizationComponent {
private:
    std::string name;

public:
    Employee(const std::string& name) : name(name) {}
    int getEmployeeCount() override {
        return 1;
    }
};

// 组合节点:部门
class Department : public OrganizationComponent {
private:
    std::string name;
    std::vector<OrganizationComponent*> children;

public:
    Department(const std::string& name) : name(name) {}
    void add(OrganizationComponent* component) {
        children.push_back(component);
    }
    int getEmployeeCount() override {
        int count = 0;
        for (OrganizationComponent* component : children) {
            count += component->getEmployeeCount();
        }
        return count;
    }
};

int main() {
    // 创建组织结构
    Department company("Company");

    Department hrDepartment("HR Department");
    hrDepartment.add(new Employee("Alice"));
    hrDepartment.add(new Employee("Bob"));

    Department engineeringDepartment("Engineering Department");
    engineeringDepartment.add(new Employee("Charlie"));
    engineeringDepartment.add(new Employee("David"));
    engineeringDepartment.add(new Employee("Eve"));

    company.add(&hrDepartment);
    company.add(&engineeringDepartment);

    // 计算公司总人数
    std::cout << "Total employees: " << company.getEmployeeCount() << std::endl;

    return 0;
}

在这个例子中,Employee 类表示叶子节点(员工),而 Department 类表示组合节点(部门)。无论是叶子节点还是组合节点,它们都实现了统一的接口 OrganizationComponent。这样,我们可以将它们放入同一个树形结构中,而不需要在处理它们的时候区分它们的类型。

标签:--,c++,nmsp2,Add,pdir1,File,FileSystem,new,设计模式
From: https://www.cnblogs.com/bwbfight/p/18225111

相关文章

  • 学术图表的基本配色方法
    不论是商业图表还是专业图表,图表的配色都极其关键。图表配色主要有彩色和黑白两种配色方案。刘万祥老师曾提出:“在我看来,普通图表与专业图表的差别,很大程度就体现在颜色运用上。”对于科学图表,大部分国内的期刊杂志要求黑白的论文图表;而国外大部分的期刊杂志允许彩色的图......
  • ICDE’24|中国企业首获最佳论文,详解PolarDB Serverless如何在0.5秒内实现跨机迁移
    以下文章来源于阿里云开发者作者陈浩、章颖强引言数据库领域顶会ICDE2024于5月13-17日在荷兰乌特勒支(Utrecht,Netherlands)举办。ICDE(TheInternationalConferenceonDataEngineering) 与VLDB、SIGMOD被公认为是国际数据管理领域三大顶级学术会议,此次在荷兰召开......
  • R语言学习 - 箱线图(小提琴图、抖动图、区域散点图)
    箱线图箱线图是能同时反映数据统计量和整体分布,又很漂亮的展示图。在2014年的NatureMethod上有2篇Correspondence论述了使用箱线图的好处和一个在线绘制箱线图的工具。就这样都可以发两篇Naturemethod,没天理,但也说明了箱线图的重要意义。下面这张图展示了Barplot、Box......
  • 9-绘制折线图
    简单折线图的绘制关于图表标题显示不出中文的情况:我是先找到文件——安装python的文件夹/Lib/site_packages/matlpotlib/mpl-data/matplotlibrc用记事本打开它,修改一个地方——查找#font.family把它后面的内容改为Microsoft Yahei但是我改完之后还是没有什么效果然后......
  • Python实现SMA黏菌优化算法优化XGBoost回归模型(XGBRegressor算法)项目实战
    说明:这是一个机器学习实战项目(附带数据+代码+文档+视频讲解),如需数据+代码+文档+视频讲解可以直接到文章最后获取。1.项目背景黏菌优化算法(Slimemouldalgorithm,SMA)由Li等于2020年提出,其灵感来自于黏菌的扩散和觅食行为,属于元启发算法。具有收敛速度快,寻优能力强的特点。主......
  • Python实现SMA黏菌优化算法优化LightGBM回归模型(LGBMRegressor算法)项目实战
    说明:这是一个机器学习实战项目(附带数据+代码+文档+视频讲解),如需数据+代码+文档+视频讲解可以直接到文章最后获取。1.项目背景黏菌优化算法(Slimemouldalgorithm,SMA)由Li等于2020年提出,其灵感来自于黏菌的扩散和觅食行为,属于元启发算法。具有收敛速度快,寻优能力强的特点。主......
  • Java的JDBC编程
     博主主页: 码农派大星.  数据结构专栏:Java数据结构 数据库专栏:MySQL数据库关注博主带你了解更多数据结构知识1.Java的数据库编程:JDBC数据库驱动包:不同的数据库,对应不同的编程语言提供了不同的数据库驱动包,如:MySQL提供了Java的驱动包mysql-connector-java,需......
  • 【c语言】指针就该这么学(1)
    ......
  • 初识C语言第三十天——设计三子棋游戏
    目录一.设计游戏框架1.打印游戏菜单2.输入选择判断(玩游戏/游戏结束/输入错误重新输入)  二、玩游戏过程设计1.设计棋格存放棋子——二维数组2.初始化棋盘——初始化为空格3.打印棋盘——本质上就是打印数组4.游戏过程——1.玩家走棋2.判断结果 3.电脑走棋4.判断结......
  • if,switch分支结构和while循环
    程序设计三种结构顺序结构分支结构做判断,做选择if(条件){语句块;//条件为真时执行语句块}如果语句块只有一条语句,可以不加大括号(不推荐)要求if语句中不能省略括号,且括号成对出现二个里选择一个(2选1)if(条件1){    语句块1;}else{    语句块2;}......