我又又又談了一期麥當勞,麥當勞看到了記得打錢😂
引入
- 商品類別樹的節點被分成兩種,一種是容器節點,另一種是葉子節點。
- 容器節點可以包含其他容器節點或者葉子節點
組合模式
- 組合模式有時又叫做部分——整體模式(Part-Whole)
。組合模式將對象組織到樹結構中,可以用來描述整體與部分的關係。組合模式可以使客戶端將單純元素與複合元素同等看待。 - 一個樹結構由兩種節點組成:樹枝節點和樹葉節點。樹枝節點可以有子節點,而一個樹葉節點不可以有子節點。除了根節點外,其它節點有且只有一個父節點。
模式結構
- 抽象構件(Component)角色
這是一個抽象角色,它給參與組合的對象規定一個接口。這個角色給出共有接口及其默認行爲。 - 樹葉構件(Leaf) 角色
代表參加組合的樹葉對象。一個樹葉對象沒有下級子對象。 - 樹枝構件(Composite)角色
代表參加組合的有子對象的對象,並給出樹枝構件對象的行爲。
示意性代碼
//抽象節點類 abstract class Component { protected string name; public Component(string name) { this.name = name; } public abstract void Add(Component c); public abstract void Remove(Component c); public abstract void Display(int depth); } //葉子節點類 class Leaf:Component { public Leaf(string name) : base(name) { } public override void Add(Component c) { Console.WriteLine("Cannot add to a leaf"); } public override void Remove(Component c) { Console.WriteLine("Cannot remove from a leaf"); } public override void Display(int depth) { Console.WriteLine(new String('-',depth)+name); } } //組合類 class Composite : Component { private List<Component> children = new List<Component>(); public Composite(string name) : base(name) { } public override void Add(Component c) { children.Add(c); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); foreach(Component component in children) { component.Display(depth + 2); } } public override void Remove(Component c) { children.Remove(c); } } class Program { static void Main(string[] args) { Composite root = new Composite("root"); root.Add(new Leaf("LeafA")); root.Add(new Leaf("LeafB")); Composite comp = new Composite("CompositeX"); comp.Add(new Leaf("LeafXA")); comp.Add(new Leaf("LeafXB")); root.Add(comp); Composite comp2 = new Composite("CompositeXY"); comp2.Add(new Leaf("LeafXYA")); comp2.Add(new Leaf("LeafXYB")); comp.Add(comp2); root.Add(new Leaf("LeafC")); Leaf leaf = new Leaf("LeafD"); root.Add(leaf); root.Remove(leaf); root.Display(1); Console.Read(); } }
認識組合模式
- 組合模式的目的
讓客戶端不再區分操作的是組合對象還是葉子對象,而是以一種統一的方式來操作 - 對象樹
組合模式會組合出樹形結構來,這也就意味着,所有可以使用對象樹來描述或操作的功能,都可以考慮使用組合模式。比如讀取XML文件,或是對語句進行語法分析等。 - 組合模式的實現根據所實現接口的區別分爲兩種形式,分別稱爲安全模式和透明模式。組合模式可以不提供父對象的管理方法,但組合模式必須在合適的地方提供子對象的管理方法(諸如Fadd、remove、Display等)。
透明方式
- 在Component裏面聲明所有的用來管理子類對象的方法,包括add ()、remove (),以及Display ()方法。
- 優點:所有的構件類都有相同的接口。在客戶端看來,樹葉類對象與組合類對象的區別起碼在接口層次上消失了,客戶端可以同等的對待所有的對象。這就是透明形式的組合模式。
- 缺點:不夠安全,因爲樹葉類對象和合成類對象在本質上是有區別的。樹葉類對象不可能有下平個層次的對象,因此add()、remove()以及Display ()方法沒有意義,在編譯時期不會出錯,而會在運行時期纔會出錯。
安全方式
- 在Composite類裏面聲明所有的用來管理子類對象的方法
- 優點:這樣的做法是安全的做法,樹葉類型的對象根本就沒有管理子類對象的方法,因此,如果客戶端對樹葉類對象使用這些方法時,程序會在編譯時期出錯。
- 缺點:不夠透明,樹葉類和合成類將具有不同的接口
使用情況
- 需求中是體現部分與整體層次的結構時
- 希望用戶忽略組合對象與單個對象的不同,統一的使用組合結構中的所有對象時。
優點
- 定義了包含基本對象和組合對象的類層次結構
基本對象可以組合成組合對象,組合對象又能組合成更復雜的組合對象,可以不斷地遞歸組合下去,從而構成一個統一的組合對象的類層次結構 - 統一了組合對象和葉子對象
- 簡化了客戶端調用
不用區分組合對象和葉子對象 - 更容易擴展
由於客戶端是統一的面對Component來操作,因此,新定義的Composite或leaf子類能夠很容易的與已有的結構一起工作,而不需改變客戶端
缺點
很難限制組合中的組件類型
這是容易添加新的組件帶來的問題,在需要檢測組件類型的時候,使得我們不能依靠編譯期的類型約束來完成,必須在運行期間動態檢測
本質
同意葉子對象和組合對象
實例
麥當勞的食物的例子:
其中圓形爲枝節點
菱形爲葉節點
抽象節點
package 組合模式;
abstract public class Node {
protected String Node_Name;
public Node(String node_Name) {
Node_Name = node_Name;
}
abstract public void add_Node(Node node);
abstract public void remove_Node(Node node);
abstract public void show();
}
葉節點
package 組合模式;
public class Leaf_Node extends Node{
public Leaf_Node(String node_Name) {
super(node_Name);
}
@Override
public void add_Node(Node node) {
// TODO Auto-generated method stub
System.out.println("Warning:此食物已經爲最細化分類,不能進一步分類");
}
@Override
public void remove_Node(Node node) {
// TODO Auto-generated method stub
System.out.println("Warning:此食物已經爲最細化分類,無子分類"); //暗示伍茲不行?玩梗!
}
@Override
public void show() {
System.out.println(" "+Node_Name);
}
}
枝節點
package 組合模式;
import java.util.ArrayList;
import java.util.List;
public class Branch_Node extends Node {
List<Node> Node_List=new ArrayList<Node>();
public Branch_Node(String node_Name) {
super(node_Name);
}
@Override
public void add_Node(Node node) {
Node_List.add(node);
}
@Override
public void remove_Node(Node node) {
Node_List.remove(node);
}
@Override
public void show() {
System.out.println("+"+Node_Name);
for(Node node:Node_List)
{
System.out.print(" ");
node.show();
}
}
}
客戶端
package 組合模式;
public class Client {
public static void main(String[] args) {
Node Main_Food=new Branch_Node("主食");
Node Hamburger=new Branch_Node("漢堡");
Node Sandwich=new Branch_Node("三明治");
Node JTHB=new Leaf_Node("雞腿堡");
Node NRHB=new Leaf_Node("牛肉堡");
Node HYSMZ=new Leaf_Node("黃油三明治");
Node TLSMZ=new Leaf_Node("甜辣三明治");
Sandwich.add_Node(HYSMZ);
Sandwich.add_Node(TLSMZ);
Hamburger.add_Node(JTHB);
Hamburger.add_Node(NRHB);
Main_Food.add_Node(Sandwich);
Main_Food.add_Node(Hamburger);
Main_Food.show();
}
}