1. 程式人生 > >設計者模式詳解--組合模式

設計者模式詳解--組合模式

param .cn ride 角色 [] 總結 code 方式 bstr

1. 概述

  將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。

2. 解決的問題

  當希望忽略單個對象和組合對象的區別,統一使用組合結構中的所有對象(將這種“統一”性封裝起來)。

3. 組合模式中的角色

  3.1 組合部件(Component):它是一個抽象角色,為要組合的對象提供統一的接口。

  3.2 葉子(Leaf):在組合中表示子節點對象,葉子節點不能有子節點。

  3.3 合成部件(Composite):定義有枝節點的行為,用來存儲部件,實現在Component接口中的有關操作,如增加(Add)和刪除(Remove)。

4. 模式解讀

  4.1 組合模式的類圖

  技術分享圖片

  4.2 組合模式的實現代碼

    /// <summary>
    /// 一個抽象構件,聲明一個接口用於訪問和管理Component的子部件
    /// </summary>
    public abstract class Component
    {
        protected string name;

        public Component(string name)
        {
            this.name = name;
        }

        /// <summary>
        /// 增加一個節點
        /// </summary>
        /// <param name="component"></param>
        public abstract void Add(Component component);

        /// <summary>
        /// 移除一個節點
        /// </summary>
        /// <param name="component"></param>
        public abstract void Remove(Component component);

        /// <summary>
        /// 顯示層級結構
        /// </summary>
        public abstract void Display(int level);
    }

    /// <summary>
    /// 葉子節點
    /// </summary>
    public class Leaf : Component
    {
        public Leaf(string name)
            : base(name)
        { }

        /// <summary>
        /// 由於葉子節點沒有子節點,所以Add和Remove方法對它來說沒有意義,但它繼承自Component,這樣做可以消除葉節點和枝節點對象在抽象層次的區別,它們具備完全一致的接口。
        /// </summary>
        /// <param name="component"></param>
        public override void Add(Component component)
        {
            Console.WriteLine("Can not add a component to a leaf.");
        }

        /// <summary>
        /// 實現它沒有意義,只是提供了一個一致的調用接口
        /// </summary>
        /// <param name="component"></param>
        public override void Remove(Component component)
        {
            Console.WriteLine("Can not remove a component to a leaf.");
        }

        public override void Display(int level)
        {
            Console.WriteLine(new string(‘-‘,level) + name);
        }
    }

    /// <summary>
    /// 定義有枝節點的行為,用來存儲部件,實現在Component接口中對子部件有關的操作
    /// </summary>
    public class Composite : Component
    {
        public Composite(string name)
            : base(name)
        { }

        /// <summary>
        /// 一個子對象集合,用來存儲其下屬的枝節點和葉節點
        /// </summary>
        private List<Component> children = new List<Component>();

        /// <summary>
        /// 增加子節點
        /// </summary>
        /// <param name="component"></param>
        public override void Add(Component component)
        {
            children.Add(component);
        }

        /// <summary>
        /// 移除子節點
        /// </summary>
        /// <param name="component"></param>
        public override void Remove(Component component)
        {
            children.Remove(component);
        }

        public override void Display(int level)
        {
            Console.WriteLine(new string(‘-‘, level) + name);

            // 遍歷其子節點並顯示
            foreach (Component component in children)
            {
                component.Display(level+2);
            }
        }
    }

  4.3 客戶端代碼

    class Program
    {
        static void Main(string[] args)
        {
            // 生成樹根,並為其增加兩個葉子節點
            Component root = new Composite("Root");
            root.Add(new Leaf("Leaf A in Root"));
            root.Add(new Leaf("Leaf B in Root"));

            // 為根增加兩個枝節點
            Component branchX = new Composite("Branch X in Root");
            Component branchY = new Composite("Branch Y in Root");
            root.Add(branchX);
            root.Add(branchY);

            // 為BranchX增加頁節點
            branchX.Add(new Leaf("Leaf A in Branch X"));

            // 為BranchX增加枝節點
            Component branchZ = new Composite("Branch Z in Branch X");
            branchX.Add(branchZ);

            // 為BranchY增加葉節點
            branchY.Add(new Leaf("Leaf in Branch Y"));

            // 為BranchZ增加葉節點
            branchZ.Add(new Leaf("Leaf in Branch Z"));

            // 顯示樹
            root.Display(1);

            Console.Read();
        }
    }

  運行結果

  技術分享圖片

5. 透明方式與安全方式

  5.1 透明方式:在Component中聲明所有來管理子對象的方法,其中包括Add,Remove等。這樣實現Component接口的所有子類都具備了Add和Remove方法。這樣做的好處是葉節點和枝節點對於外界沒有區別,它們具備完全一致的接口。

  5.2 安全方式:在Component中不去聲明Add和Remove方法,那麽子類的Leaf就不需要實現它,而是在Composit聲明所有用來管理子類對象的方法。

  5.3 兩種方式有缺點:對於透明方式,客戶端對葉節點和枝節點是一致的,但葉節點並不具備Add和Remove的功能,因而對它們的實現是沒有意義的;對於安全方式,葉節點無需在實現Add與Remove這樣的方法,但是對於客戶端來說,必須對葉節點和枝節點進行判定,為客戶端的使用帶來不便。

6. 模式總結

  6.1 優點

    6.1.1 使客戶端調用簡單,它可以一致使用組合結構或是其中單個對象,簡化了客戶端代碼。

    6.1.2 容易在組合體內增加對象部件。客戶端不必因加入了新的部件而更改代碼。有利於功能的擴展。

  6.2 缺點

    6.2.1 需要抉擇使用透明方式還是安全方式。

    6.2.2 透明方式違背了面向對象的單一職責原則;安全方式增加了客戶需要端判定的負擔。

  6.3 適用場景

    6.3.1 當想表達對象的部分-整體的層次結構時

    6.3.3 希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象時。

原文鏈接:https://www.cnblogs.com/wangjq/archive/2012/07/06/2579244.html

設計者模式詳解--組合模式