组合模式将对象组合成树形结构来表现“整体/部分”的层次结构,并且可以像处理单个对象一样处理整个树形结构。当需求场景是体现部分与整体层次的结构时;或者你希望用户可以忽略组合对象与单个对象的不同,而统一的使用组合结构中的所有对象时,就应该考虑用组合模式了。
组合模式包含以下几个角色:
抽象构件(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