前置文章: 设计模式的原则
其他设计模式:用心理解设计模式专栏
设计模式相关代码已统一放至 我的 Github
一、定义
结构型模式之一。
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
(将对象组合成树形结构以表示 “整体-部分” 的层次结构,组合模式使客户端对单个对象和组合对象的操作一致。)
二、结构解析
组合模式的一般结构有三种角色: 抽象组件、叶节点、枝节点。
抽象组件(Component):负责定义可供客户统一操作的接口方法。包含增加、移除子节点等必需的接口方法。
叶节点(Leaf):继承抽象组件,对增加、移除子节点的接口方法给出空实现或抛出异常。重写其他接口方法,以支持对叶节点的特别操作。
枝节点(Composite):继承抽象组件,聚合/持有一组抽象组件类型的成员,实际可接收叶节点或其他枝节点。真正实现增加、移除子节点的接口方法。重写其他接口方法,以支持针对枝节点的特别操作,常含有递归逻辑。
三、评价
组合模式定义了一种 “整体包含部分,部分又可以包含整体” 的树状结构,客户可以对整体和部分统一对待。
组合模式中,各节点的层级分明,扩展移除也非常容易。
组合模式非常常见,如 文件夹和文件系统、Unity的Hierachy视图等。
组合模式又分为 透明型组合模式 和 安全型组合模式。
透明组合模式,即如上文 二 中描述的那样。
安全型组合模式,与之不同的是:它在抽象组件中不再定义 “增加、移除子节点等接口方法”,这些方法只在枝节点类中扩展实现。优点是叶节点不再继承它不需要的一些接口方法,变得更安全。缺点是丧失了外部对枝和叶操作的一致性,需要在操作时先辨别是枝还是叶,再分别对待。
四、实现
额外增加了depth属性,以说明层级分明,扩展移除也非常容易。
实现结果预览(前缀的 “-” 数量代表其深度):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Composite
{
//抽象组件
public abstract class Component
{
protected string name; //名称
public int depth = 0; //自身深度
public Component(string name)
{
this.name = name;
}
public abstract void Add(Component component);
public abstract void Remove(Component component);
public abstract Component GetChild(int index);
public abstract void RecurveShow();
//-------------------下面是本设计模式的非主要方法----------------------
public void Operate()
{
Debug.Log(GetDepthStr() + GetName());
}
public string GetDepthStr()
{
string depthStr = "";
for (int i = 0; i < this.depth; i++)
{
depthStr += "- ";
}
return depthStr;
}
public string GetName()
{
return this.name;
}
public abstract void RefreshDepth(int depth);
}
//叶节点
public class Leaf : Component
{
public Leaf(string name) : base(name) { }
public override void Add(Component component)
{
throw new NotImplementedException();
}
public override void Remove(Component component)
{
throw new NotImplementedException();
}
public override Component GetChild(int index)
{
throw new NotImplementedException();
}
public override void RecurveShow()
{
this.Operate();
}
public override void RefreshDepth(int depth)
{
this.depth = depth;
}
}
//枝节点
public class Composite : Component
{
private List<Component> children = new List<Component>();
public Composite(string name) : base(name) { }
public override void Add(Component component)
{
component.RefreshDepth(this.depth + 1);
children.Add(component);
}
public override void Remove(Component component)
{
children.Remove(component);
}
public override Component GetChild(int index)
{
return children[index];
}
public override void RecurveShow()
{
this.Operate();
foreach (Component child in children)
{
child.RecurveShow();
}
}
public override void RefreshDepth(int depth)
{
this.depth = depth;
foreach (Component child in children)
{
child.RefreshDepth(this.depth + 1);
}
}
}
public class Client
{
static public void Main()
{
//创建根节点,并加入两个叶节点
Composite root = new Composite("root");
root.Add(new Leaf("LeafA"));
root.Add(new Leaf("LeafB"));
//创建带有叶节点的枝节点,最后加入根节点
Composite compX = new Composite("CompositeX");
compX.Add(new Leaf("LeafC"));
compX.Add(new Leaf("LeafD"));
compX.Add(new Leaf("LeafE"));
compX.Remove((Leaf)compX.GetChild(1));
root.Add(compX);
//创建更深层的带有叶节点的枝节点,最后加入根节点
Composite compY = new Composite("CompositeY");
Composite compZ = new Composite("CompositeZ");
compX.Add(compY);
compY.Add(compZ);
compZ.Add(new Leaf("LeafF"));
//递归显示
root.RecurveShow();
}
}
}