设计模式(008)结构型之组合模式

文章介绍了组合模式在创建具有“整体/部分”层次结构的对象时的应用,以文件系统为例,展示了如何用C++和Java实现。组合模式允许统一处理单个对象和组合对象,简化了代码并提供了灵活性。示例中,文件和文件夹被组织成树形结构,可以递归打印所有名称,并演示了添加和删除文件的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        组合模式将对象组合成树形结构来表现“整体/部分”的层次结构,并且可以像处理单个对象一样处理整个树形结构。当需求场景是体现部分与整体层次的结构时;或者你希望用户可以忽略组合对象与单个对象的不同,而统一的使用组合结构中的所有对象时,就应该考虑用组合模式了。
组合模式包含以下几个角色:
抽象构件(Component):定义组合中所有对象的通用接口,可以是抽象类或者接口,包含了一些基本操作方法,如添加子节点、删除子节点、获取子节点等。
叶子节点(Leaf):组合中的叶子节点,表示最基本的单个对象。
容器节点(Composite):组合中的容器节点,包含了一组子节点,可以是叶子节点或者其他容器节点。
使用组合模式的优点包括:
可以将复杂的层次结构组织为树形结构,简化了代码的复杂性。可以统一处理单个对象和组合对象,使得代码更加灵活。可以在不改变现有代码的情况下增加新的组合对象。

1、场景设计

实现场景:用组合模式创建一个“文件系统”类,它可以包含文件夹和文件,并且可以递归地打印出所有文件和文件夹的名称。

2、C++实现

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

//文件系统接口
class FileSystemComponent {
    public:
        virtual ~FileSystemComponent() = default;
        //leave表示层级
        virtual void printName(int leave) const = 0;
};

//文件
class File:public FileSystemComponent {
    public:
        explicit File(std::string name) : name_(std::move(name)) {}

        void printName(int leave) const override {
            std::string padding = "";
            for(int i=0;i<leave;i++){
                padding = padding + "\t";
            }
            std::cout << padding << name_ << std::endl;
        }

    private:
        std::string name_;
};

//文件夹 里面可能包含多个文件或文件夹
class Folder:public FileSystemComponent {
    public:
        explicit Folder(std::string name) : name_(std::move(name)) {}

        void printName(int leave) const override {

            std::string padding = "";
            for(int i=0;i<leave;i++){
                padding = padding + "\t";
            }
            std::cout << padding << name_ << std::endl;

            for (const auto& component : component_s) {
                component->printName(leave+1);
            }
        }

        void addComponent(FileSystemComponent* component){
            component_s.push_back(component);
        }

        void removeComponent(FileSystemComponent* component){
            component_s.erase(std::remove(component_s.begin(), component_s.end(), component), component_s.end());
        }

    private:
        std::string name_;
        std::vector<FileSystemComponent*> component_s;
};

int main() {
    // 创建若干文件和文件夹
    File* file1 = new File("file1.txt");
    File* file2 = new File("file2.txt");
    File* file3 = new File("file3.txt");
    File* file4 = new File("file4.txt");
    File* file5 = new File("file5.txt");
    Folder* folder1 = new Folder("folder1");
    Folder* folder2 = new Folder("folder2");
    Folder* folder3 = new Folder("folder3");
    Folder* root = new Folder("root");

    // 创建层级关系
    folder1->addComponent(file1);
    folder1->addComponent(file2);
    folder2->addComponent(file3);
    folder3->addComponent(file4);
    folder3->addComponent(file5);
    folder2->addComponent(folder1);
    root->addComponent(folder2);
    root->addComponent(folder3);

    // 打印所有的文件和文件夹 root属于层级0。本示例中层级仅用于规范输出格式,便于观察
    root->printName(0);
    std::cout << "------ delete some file -----"<<std::endl;
    folder1->removeComponent(file1);
    folder3->removeComponent(file4);
    root->printName(0);

    delete file1;
    delete file2;
    delete file3;
    delete file4;
    delete file5;
    delete folder1;
    delete folder2;
    delete folder3;
    delete root;

    return 0;
}

输出:

3、Java实现

CompositeDemo.java
package structuralpattern.composite;

import java.util.ArrayList;
import java.util.List;

//文件系统接口
interface FileSystemComponent {
    //leave表示层级
    void printName(int leave);
}

//文件
class File implements FileSystemComponent {
    private String name;
    public File(String name) {
        this.name = name;
    }
    @Override
    public void printName(int leave) {
        String padding = "";
        for(int i=0;i<leave;i++){
            padding = padding + "\t";
        }
        System.out.println(padding + name);
    }
}

//文件夹 里面可能包含多个文件或文件夹
class Folder implements FileSystemComponent {
    private String name;
    private List<FileSystemComponent> components;

    public Folder(String name) {
        this.name = name;
        this.components = new ArrayList<>();
    }

    public void addComponent(FileSystemComponent component) {
        components.add(component);
    }

    public void removeComponent(FileSystemComponent component) {
        components.remove(component);
    }

    @Override
    public void printName(int leave) {
        String padding = "";
        for(int i=0;i<leave;i++){
            padding = padding + "\t";
        }
        System.out.println(padding + name);
        for (FileSystemComponent component:components) {
            component.printName(leave+1);
        }
    }
}

public class CompositeDemo {
    public static void main(String[] args) {
        // 创建若干文件和文件夹
        File file1 = new File("file1.txt");
        File file2 = new File("file2.txt");
        File file3 = new File("file3.txt");
        File file4 = new File("file4.txt");
        File file5 = new File("file5.txt");
        Folder folder1 = new Folder("folder1");
        Folder folder2 = new Folder("folder2");
        Folder folder3 = new Folder("folder3");
        Folder root = new Folder("root");

        // 创建层级关系
        folder1.addComponent(file1);
        folder1.addComponent(file2);
        folder2.addComponent(file3);
        folder3.addComponent(file4);
        folder3.addComponent(file5);
        folder2.addComponent(folder1);
        root.addComponent(folder2);
        root.addComponent(folder3);

        // 打印所有的文件和文件夹 root属于层级0。本示例中层级仅用于规范输出格式,便于观察
        root.printName(0);
        System.out.println("------ delete some file -----");
        folder1.removeComponent(file1);
        folder3.removeComponent(file4);
        root.printName(0);
    }
}

 输出显示:

root
	folder2
		file3.txt
		folder1
			file1.txt
			file2.txt
	folder3
		file4.txt
		file5.txt
------ delete some file -----
root
	folder2
		file3.txt
		folder1
			file2.txt
	folder3
		file5.txt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值