组合模式
将对象组合成树形结构,以表示“部分-整体”的层次结构。
适合的场景
想表达层级结构,如文件夹、UI控件、游戏物体等等
希望统一操作单个对象和组合对象,不区分处理方式
想让“整体”和“部分”都遵循相同的接口
Godot节点树/Unity场景树就是一个典型的例子!
基本结构
Component(组件接口):统一接口,可以是叶子也可以是组合
Leaf(叶子节点):没有子节点
Composite(组合节点):包含子节点,并实现统一接口
示例
csharp
// 抽象组件
abstract class FileSystemItem
{
public string Name { get; }
public FileSystemItem(string name) => Name = name;
public abstract void Display(int indent = 0);
}
// 叶子节点:文件
class FileItem : FileSystemItem
{
public FileItem(string name) : base(name) {}
public override void Display(int indent)
{
Console.WriteLine(new string(' ', indent) + Name);
}
}
// 组合节点:文件夹
class Folder : FileSystemItem
{
private List<FileSystemItem> _children = new();
public Folder(string name) : base(name) {}
public void Add(FileSystemItem item) => _children.Add(item);
public override void Display(int indent)
{
Console.WriteLine(new string(' ', indent) + Name);
foreach (var item in _children)
item.Display(indent + 2);
}
}
// 使用方法
var root = new Folder("Root");
root.Add(new FileItem("readme.txt"));
var sub = new Folder("Assets");
sub.Add(new FileItem("player.png"));
sub.Add(new FileItem("enemy.png"));
root.Add(sub);
root.Display();
/*
输出结果
Root
readme.txt
Assets
player.png
enemy.png
*/GDScript示例
gdscript
class UIComponent extends Node:
func display(indent := 0):
print(" ".repeat(indent) + name)
class UIButton extends UIComponent:
func display(indent := 0):
print(" ".repeat(indent) + "Button: " + name)
class UIPanel extends UIComponent:
func display(indent := 0):
print(" ".repeat(indent) + "Panel: " + name)
for child in get_children():
if child is UIComponent:
child.display(indent + 2)
# 使用
func _ready():
var root := UIPanel.new()
root.name = "Main"
var btn1 := UIButton.new()
btn1.name = "Start"
var sub_panel := UIPanel.new()
sub_panel.name = "Settings"
var btn2 := UIButton.new()
btn2.name = "Audio"
sub_panel.add_child(btn2)
root.add_child(btn1)
root.add_child(sub_panel)
root.display()