【設計模式】組合模式

定義


組合模式,又稱為部分整體模式,把具有相似的一組對象
當做一個對象處理,用一種樹狀的結構來組合對象,再提供統一
的方法去訪問相似的對象,以此忽略掉對象與對象容器間的差別。

UML圖

  • Component :抽象組件,為組合中的對象聲明接口,讓客戶端
    可以通過這個接口來訪問和管理整個對象結構,可以在裏面為定義的
    功能提供缺省的實現,比如上面的AbstractMenu類。
  • Composite :容器組件,繼承抽象組件,實現抽象組件中與
    葉子組件相關的操作,比如上面的Menu類重寫了get,set方法。
  • Leaf:葉子組件,定義和實現葉子對象的行為,不再包含其它
    的子節點對象

可以將組合模式理解成,樹葉跟樹枝 樹枝會長出很多分支,樹葉卻不會長出樹枝 也就是說,樹葉(Left)就是最小單位,而樹枝(Composite)則是它的上一級,用來儲存樹葉用的,而Component可以當作這棵樹中的根,這棵樹所有子節點都會實現它

應用場合

其他日常看到的例子的話有【文件、文件夾】,【菜單與菜單上的菜】
只要是

  1. 想表示對象的部分-整體層次的結構
  2. 忽略組合對象(樹枝)與單個對象(樹葉)的不同,用戶統一的使用組合結構中的所有對象就可以考慮使用組合模式,像是Unity內物件結構


另外,可以使用組合對象來得到、搜尋當中的物件,但如果有頻繁的搜尋需求,可以用緩存來改善效率。
像是在Unity內,如果搜尋的話使用GameObject.Find(“xxx”),會搜尋所有物件(紅框部摁),物件一多效率就不好,但如果只將一小部分做成組合模式,階層式的管理,只需要搜尋內部那一小部分(綠框部分),效率就會改善許多。

最後附上code參考

Component 抽象組件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Component
{
protected string mName;
public string name { get { return mName; } }
public Component(string name)
{
mName = name;
}

protected List<Component> mChildren = new List<Component>();
public abstract void AddChild(Component component);
public abstract void RemoveChild(Component component);
public abstract Component GetChild(int index);
}

Composite 容器組件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Composite : Component
{

public Composite(string name) : base(name) { }

public override void AddChild(Component component)
{
mChildren.Add(component);
}

public override void RemoveChild(Component component)
{
mChildren.Remove(component);
}

public override Component GetChild(int index)
{
return mChildren[index];
}

}

葉子組件 Left

1
2
3
4
5
6
7
8
9
10
public class Leaf : Component
{
public Leaf(string name) : base(name) { }

public override void AddChild(Component component) { return; } //不需要實作

public override void RemoveChild(Component component) { return; } //不需要實作

public override Component GetChild(int index) { return null; }
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Client : MonoBehaviour {


private void Start()
{
Composite root = new Composite("RootGameObject");

Leaf left1 = new Leaf("A");
Leaf left2 = new Leaf("B");
Composite gameObject1 = new Composite("GameObject1");

root.AddChild(left1);
root.AddChild(gameObject1);
root.AddChild(left2);


Leaf child1 = new Leaf("C");
Leaf child2 = new Leaf("D");
gameObject1.AddChild(child1);
gameObject1.AddChild(child2);

Debug.Log(root.GetChild(0).GetChild(0).name);
}


}