『設計模式』 又談麥當勞的食品--組合模式(Composite)

我又又又談了一期麥當勞,麥當勞看到了記得打錢😂

引入

  • 商品類別樹的節點被分成兩種,一種是容器節點,另一種是葉子節點。
  • 容器節點可以包含其他容器節點或者葉子節點

組合模式

  • 組合模式有時又叫做部分——整體模式(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();
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章