十、组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它允许将对象组合成树形结构来表示“部分-整体”的层次关系。组合模式能够让客户端以统一的方式对待单个对象和对象集合,使得客户端在处理复杂树形结构的时候,可以以相同的方式对待单个对象和多个对象组合。
主要组成部分:
-
抽象组件(Component):
- 定义了 leaf 和 composite 的对象共同实现的接口。在这里你可以定义接口的方法。
-
叶子(Leaf):
- 实现了抽象组件,代表组合中的叶子节点。叶子节点没有子节点。
-
组合(Composite):
- 也实现了抽象组件,代表可以有子节点的树节点。组合节点可以包含叶子或其他组合节点。
-
客户端(Client):
- 使用组合结构的代码,通常通过接口与树结构交互。
优点:
- 一致性:客户端可以以一致的方式对待所有组成部分,无论是单个对象还是组合对象。
- 易于添加新组件:可以轻松地增加新的叶子或组合,无需修改现有代码。
- 简化客户端代码:客户端代码可以简单地使用组合结构,不需要关注部分和整体的区别。
使用场景:
- 需要表示对象的树形结构。
- 客户端希望以相同的方式处理单个对象和组合对象。
- 需要在运行时增加或删除对象。
JAVA:
创建一个文件系统的结构
// 文件系统-抽象组件
public abstract class FileSystemComponent {
protected String name; //名称
//构造
public FileSystemComponent(String name){
this.name = name;
}
//抽象文件详情方法
public abstract void showDetails();
}
// 叶子类-文件
public class File extends FileSystemComponent{
public File(String name) {
super(name);
}
@Override
public void showDetails() {
System.out.println("File: " + name);
}
}
// 组合类
public class Folder extends FileSystemComponent{
private List<FileSystemComponent> components = new ArrayList<>();
public Folder(String name) {
super(name);
}
// 添加文件/文件夹
public void addComponent(FileSystemComponent component) {
components.add(component);
}
// 删除文件
public void removeComponent(FileSystemComponent component) {
components.remove(component);
}
@Override
public void showDetails() {
System.out.println("Folder: " + name);
for (FileSystemComponent component : components) {
component.showDetails();
}
}
}
@Test(description = "组合模式")
public void compositeTest(){
// 创建文件和文件夹
File file1 = new File("File1.txt");
File file2 = new File("File2.txt");
Folder folder1 = new Folder("Folder1");
folder1.addComponent(file1);
folder1.addComponent(file2);
File file3 = new File("File3.txt");
Folder folder2 = new Folder("Folder2");
folder2.addComponent(file3);
// 创建根文件夹
Folder rootFolder = new Folder("RootFolder");
rootFolder.addComponent(folder1);
rootFolder.addComponent(folder2);
// 显示文件夹结构
rootFolder.showDetails();
}
GO:
公司的人员组织就是一个典型的树状的结构,现在假设我们现在有部分,和员工,两种角色,一个部门下面可以存在子部门和员工,员工下面不能再包含其他节点。
我们现在要实现一个统计一个部门下员工数量的功能
package composite
// IOrganization 组织接口,都实现统计人数的功能
type IOrganization interface {
Count() int
}
// Employee 员工
type Employee struct {
Name string
}
// Count 统计人数
func (e Employee) Count() int {
return 1
}
// Department 部门
type Department struct {
Name string
SubOrganizations []IOrganization
}
// Count 人数统计
func (d Department) Count() int {
c := 0
for _, org := range d.SubOrganizations {
c += org.Count()
}
return c
}
// AddSub 添加子节点
func (d *Department) AddSub(o IOrganization) {
d.SubOrganizations = append(d.SubOrganizations, o)
}
// NewOrganization 构建组织架构 demo
func NewOrganization() IOrganization {
root := &Department{Name: "root"}
for i := 0; i < 10; i++ {
root.AddSub(&Employee{})
root.AddSub(&Department{Name: "sub", SubOrganizations: []IOrganization{&Employee{}}})
}
return root
}
package composite
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestComposite(t *testing.T) {
got := NewOrganization().Count()
assert.Equal(t, 20, got)
}