组合模式(Composite Pattern)是一种结构型设计模式,它允许将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端可以以统一的方式处理单个对象和对象组合,从而使得在树形结构中处理对象更加简单和灵活。
组合模式包括以下角色:
- 抽象组件(Component):定义了组合中叶子节点和容器节点的公共接口。
- 叶子节点(Leaf):表示组合中的叶子节点对象,它没有子节点。
- 容器节点(Composite):表示组合中的容器节点对象,它有子节点,并且可以添加、删除子节点。
组合模式的优点包括:
- 统一处理对象和对象组合,使得客户端使用更加简单。
- 灵活性好,可以随时增加或删除树形结构中的对象。
- 可以方便地处理具有递归结构的数据。
简单的
假设我们要设计一个文件系统,包括文件夹和文件两种对象,其中文件夹可以包含文件和其他文件夹,而文件不能包含任何其他对象。我们可以使用组合模式来实现文件系统的设计。具体实现可以参考以下代码:
// 抽象组件
public abstract class FileSystemComponent
{
protected string name;
public FileSystemComponent(string name)
{
this.name = name;
}
public abstract void Print();
}
// 叶子节点:文件
public class File : FileSystemComponent
{
public File(string name) : base(name) {
}
public override void Print()
{
Debug.Log("File: " + name);
}
}
// 容器节点:文件夹
public class Folder : FileSystemComponent
{
private List<FileSystemComponent> children = new List<FileSystemComponent>();
public Folder(string name) : base(name) {
}
public void Add(FileSystemComponent component)
{
children.Add(component);
}
public void Remove(FileSystemComponent component)
{
children.Remove(component);
}
public override void Print()
{
Debug.Log("Folder: " + name);
foreach (var component in children)
{
component.Print();
}
}
}
// 客户端代码
public class Client
{
public void Run()
{
Folder root = new Folder("Root");
Folder folder1 = new Folder("Folder1");
Folder folder2 = new Folder("Folder2");
File file1 = new File("File1");
File file2 = new File("File2");
File file3 = new File("File3");
root.Add(folder1);
root.Add(file1);
folder1.Add(file2);
folder1.Add(folder2);
folder2.Add(file3);
root.Print();
}
}
更复杂的
假设有一个游戏中的物品系统,每个物品都有自己的属性,比如名称、描述、图标等,而且可能会有不同的类型,比如武器、防具、道具等。这些物品还可以放在背包中,背包本身也可以被视为一个物品,而且背包里面可能会有其他的物品,因此物品系统中的物品可以组合成一个树形结构。我们可以使用组合模式来实现这个系统。
- 定义一个抽象类 Item,它表示物品,其中包含了物品的基本属性和方法,比如名称、描述、图标等,以及一个 AddItem 和 RemoveItem 方法,用于添加和移除子物品:
public abstract class Item
{
public string Name {
get; set; }
public string Description {
get; set; }
public Texture2D Icon {
get; set; }
public virtual void Use() {
}
public virtual void AddItem(Item item) {
}
public virtual void RemoveItem(Item item) {
}
}
- 定义一个 Leaf 类,它表示叶子节点,也就是不可以再继续添加子物品的物品,比如道具和装备:
public class Leaf : Item
{
public override void Use()
{
Debug.Log($"Using {
Name}");
}
}
- 定义一个 Composite 类,它表示容器节点,也就是可以添加和移除子物品的物品,比如背包和武器库:
public class Composite : Item
{
private List<Item> _items = new List<Item>();
public override void Use()
{
Debug.Log($"Opening {
Name}");
foreach (var item in _items)
{
item.Use();
}
}
public override void AddItem(Item item)
{
_items.Add(item);
}
public override void RemoveItem(Item item)
{
_items.Remove(item);
}
}
- 我们可以使用这些类来创建具体的物品,比如:
var potion = new Leaf {
Name = "Potion", Description = "Restore some health" };
var sword = new Leaf {
Name = "Sword", Description = "A sharp weapon" };
var armor = new Leaf {
Name = "Armor", Description = "Provides some protection" };
var backpack = new Composite {
Name = "Backpack", Description = "A container for items" };
backpack.AddItem(potion);
backpack.AddItem(sword);
var warehouse = new Composite {
Name = "Warehouse", Description = "A storage for weapons and armors" };
warehouse.AddItem(sword);
warehouse.AddItem(armor);
- 我们就可以像操作一个普通的物品一样操作背包和仓库了,比如:
backpack.Use(); // Output: Opening Backpack\nUsing Potion\nUsing Sword
warehouse.Use(); // Output: Opening Warehouse\nUsing Sword\nUsing Armor
warehouse.AddItem(backpack);
warehouse.Use(); // Output: Opening Warehouse\nUsing Sword\nUsing Armor\nOpening Backpack\nUsing Potion\nUsing Sword