👈️上一篇:适配器模式 | 下一篇:桥接模式👉️
设计模式-专栏👈️
目 录
- 组合模式
- 定义
- 英文原话
- 直译
- 如何理解?
- 3个角色
- UML类图
- 代码示例
- 组合模式的优点
- 组合模式的使用场景
- 示例解析:文件系统
组合模式
组合模式(Composite Pattern)也叫合成模式,用来描述部分与整体的关系。
- 高层模块调用简单。一棵树形结构中的所有节点都是 Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
- 节点自由增加。使用组合模式后,如果想增加一个树枝节点、树叶节点只需要找到其父节点即可。
当我们发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。
定义
英文原话
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
直译
将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端能够统一地处理单个对象和对象的组合。
如何理解?
叶子构件和容器构件实现了抽象构件,即实现了相同的接口,用户对单个对象和组合对象的使用具有一致性。
3个角色
UML类图
组合模式(Composite Pattern)允许我们将对象组合成树形结构以表示“部分整体”的层次结构,使得客户端以统一的方式处理单个对象和对象的组合。以下是组合模式中的主要角色:
- 抽象构件(Component):它可以是接口或抽象类,为叶子和容器对象声明接口,在该接口中包含用于管理子对象的方法以及用于自身操作的方法。在组合模式中,抽象构件定义了叶子和容器构件的共同行为。
- 叶子构件(Leaf):叶子对象继承自抽象构件,它没有子节点,通常用于实现抽象构件中的业务方法。在组合结构中,叶子节点没有子节点,其实现了在抽象构件中定义的行为。
- 容器构件(Composite):容器对象也继承自抽象构件,并包含一组子构件。它实现了在抽象构件中定义的行为,并提供了添加、删除和访问其子对象的方法。容器构件可以包含其他容器或叶子,从而实现复杂的树形结构。
- 客户端(Client):通过抽象构件接口与组合结构进行交互。对于客户端而言,叶子对象和容器对象是一致的,客户端不需要区分它们。
代码示例
以下是一个简单的Java示例来说明组合模式:
// 抽象构件
public interface Component {
void operation();
}
// 叶子构件
public class Leaf implements Component{
@Override
public void operation() {
// 业务处理逻辑
System.out.println("leaf...");
}
}
// 容器构件
public class Composite implements Component {
// 构件容器
private ArrayList<Component> componentList = new ArrayList<>();
// 添加构件
public void add(Component component) {
this.componentList.add(component);
}
// 删除构件
public void remove(Component component) {
this.componentList.remove(component);
}
// 获取子构件
public ArrayList<Component> getChild() {
return this.componentList;
}
@Override
public void operation() {
// 业务逻辑
System.out.println("branch...");
}
}
// 客户端代码
public class DemoTest {
public static void main(String[] args) {
// 创建一个根节点
Composite root = new Composite();
root.operation();
// 创建树枝节点
Composite branch = new Composite();
// 创建叶子节点
Leaf leaf = new Leaf();
// 构建树形结构
root.add(branch);
branch.add(leaf);
display(root);
}
// 遍历树(递归)
public static void display(Composite root) {
for (Component c : root.getChild()) {
if(c instanceof Leaf){// 如果节点类型是叶子节点
c.operation();
}else{// 树枝节点
c.operation();
display((Composite) c);
}
}
}
}
/* Output:
branch...
branch...
leaf...
*///~
在这个例子中,我们有一个Component
接口,它定义了一个名为operation
的方法。Leaf
类实现了这个接口,并提供了具体的实现。Composite
类同样实现了Component
接口,并维护了一个子组件的列表。
组合模式的优点
- 高层模块调用简单。一棵树形机构中的所有节点都是 Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
- 节点自由增加。使用组合模式后,如果想增加一个树枝节点、树叶节点只需要找到其父节点即可。
组合模式的使用场景
使用组合模式的典型场景如下。
- 需要描述对象的部分和整体的等级结构,如树形菜单、文件和文件夹管理。
- 需要客户端忽略个体构件和组合构件的区别,平等对待所有的构件。
示例解析:文件系统
在生活中,一个常见的组合模式的例子是文件系统。文件系统中的文件和文件夹可以看作是组合模式的实现,其中文件夹可以包含文件和其他文件夹(子文件夹),而文件则不包含任何子项。
以下是使用Java实现的示例,模拟了一个简单的文件系统:
// 抽象构件:文件或文件夹
public interface FileSystemElement {
void display();
}
// 叶子构件:文件
public class File implements FileSystemElement {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println("File: " + name);
}
}
// 容器构件:文件夹
public class Folder implements FileSystemElement {
private String name;
private List<FileSystemElement> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileSystemElement element) {
children.add(element);
}
public void remove(FileSystemElement element) {
children.remove(element);
}
@Override
public void display() {
System.out.println("Folder: " + name);
for (FileSystemElement child : children) {
child.display();
}
}
}
// 客户端代码
public class DemoTest {
public static void main(String[] args) {
// 创建文件夹和文件
Folder rootFolder = new Folder("root");
Folder documentsFolder = new Folder("Documents");
Folder picturesFolder = new Folder("Pictures");
File file1 = new File("example.txt");
File file2 = new File("image.jpg");
// 将文件和文件夹添加到对应的父文件夹中
rootFolder.add(documentsFolder);
rootFolder.add(picturesFolder);
documentsFolder.add(file1);
picturesFolder.add(file2);
// 显示整个文件系统的结构
rootFolder.display();
}
}
/* Output:
Folder: root
Folder: Documents
File: example.txt
Folder: Pictures
File: image.jpg
*///~
在这个示例中,FileSystemElement
是抽象构件接口,它声明了一个display
方法用于显示文件或文件夹的信息。File
类实现了这个接口,表示一个具体的文件。Folder
类也实现了这个接口,表示一个文件夹,并且它有一个children
列表来存储其子元素(文件和文件夹)。Folder
类还提供了添加和删除子元素的方法。
在DemoTest
类的main
方法中,我们创建了一个根文件夹rootFolder
,并添加了documentsFolder
和picturesFolder
两个子文件夹。接着,我们向这两个文件夹中分别添加了一个文件和图片。最后,我们调用rootFolder
的display
方法来显示整个文件系统的结构。
这个输出展示了组合模式中的层次结构,其中文件夹可以包含文件和子文件夹,而文件则不包含任何子项。
👈️上一篇:适配器模式 | 下一篇:桥接模式👉️
设计模式-专栏👈️