面向對象編程思想-組合模式


一、引言

在軟件開發中,我們經常會遇到處理簡單對象和復合對象的情況,例如操作系統中文件目錄的處理,目錄可以包含單獨的文件,也可以包括文件夾,而文件夾里又包含着文件,如此遞歸下去或者說是分級數據結構。由於簡單對象和復合對象在功能上的區別,導致在操作過程中必須區分簡單對象和復合對象,這樣導致客戶端調用時帶來不必要的麻煩,作為客戶,希望能夠始終如一的對待簡單對象和復雜對象。組合模式就是解決這個問題的

二、組合模式

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

來看看組合模式的基本代碼結構

  abstract class Component
    {
        protected string name;
        public Component(string name)
        {
            this.name = name;
        }
        public abstract void Add(Component component);
        public abstract void Remove(Component component);
        public abstract void Display(int depth);
    }

 

  //Leaf在組合中表示葉節點對象
    class Leaf : Component
    {
        public Leaf(string name) : base(name) { }
        //由於葉子沒有在增加分枝和樹葉,所以ADD與Remove方法實現它沒有意義;
        //但可以消除葉節點和枝節點在抽象層次的區別,它們具備完全一致的接口
        public override void Add(Component component)
        {
            Console.WriteLine("葉節點不允許添加樹枝樹葉節點");
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-',depth)+name);
        }

        public override void Remove(Component component)
        {
            Console.WriteLine("由於葉節點沒有子節點,這里移除沒有任何意義");
        }
    }

 

  class Composite : Component
    {
        private List<Component> Children = new List<Component>();
        public Composite(string name) : base(name) { }
        public override void Add(Component component)
        {
            Children.Add(component);
        }
        //顯示枝節點名稱並對其下級進行遍歷
        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 component)
        {
            Children.Remove(component);
        }
    }

 

     static void Main(string[] args)
        {
            Composite root = new Composite("root");
            root.Add(new Leaf("Leaf A"));
            root.Add(new Leaf("Leaf B"));
            Composite comp = new Composite("Composite X");
            comp.Add(new Leaf("Leaf XA"));
            comp.Add(new Leaf("Leaf XB"));
            root.Add(comp);
            Composite comp2 = new Composite("Composite XY");
            comp2.Add(new Leaf("Leaf XYA"));
            comp2.Add(new Leaf("Leaf XYB"));
            comp.Add(comp2);
            root.Add(new Leaf("Leaf C"));
            Leaf leaf = new Leaf("Leaf D");
            root.Add(leaf);
            root.Remove(leaf);
            root.Display(0);
        Console.Read();
        }

結果如下圖所示:

透明方式:在Component中聲明所有管理子對象的方法,這樣實現Component的子類都有Add和Remove方法,這樣做的好處是葉節點和枝節點對於外界沒有區別,它們具備完全一致的接口,但問題也很明顯,Leaf本身沒有Add和Remove方法,實現它是沒有意義的

安全方式:在Component中不去聲明Add和Remove方法,那么子類Leaf就不需要實現它,而是在Composite中聲明所有管理子類的方法,不過由於不夠透明,樹葉類和樹枝類不具有相同的接口,客戶端調用需要相應的判斷,帶來了不便

下面是大話設計模式中公司管理系統的例子:

  public abstract class Company
    {
        protected string Name;
        public Company(string name)
        {
            this.Name = name;
        }
        public abstract void Add(Company company);
        public abstract void Remove(Company company);
        public abstract void Display(int depth);
        public abstract void LineOfDuty();
    }

 

   //具體公司類 樹枝節點
    class ConcreteCompany : Company
    {
        //一個子對象集合 用來存儲其下屬的枝節點 葉節點
        private List<Company> Children = new List<Company>();
        public ConcreteCompany(string name) : base(name) { }
        public override void Add(Company company)
        {
            Children.Add(company);
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-',depth)+Name);
            foreach (Company com in Children)
            {
                com.Display(depth+2);
            }
        }

        public override void LineOfDuty()
        {
            foreach (Company com in Children)
            {
                com.LineOfDuty();
            }
        }

        public override void Remove(Company company)
        {
            Children.Remove(company);
        }
    }

 

   //人力資源部類 樹葉節點
    class HRDepartment:Company
    {
        public HRDepartment(string name) :base(name)
        { }

        public override void Add(Company company)
        {
            
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-',depth)+Name);
        }

        public override void LineOfDuty()
        {
            Console.WriteLine($"{Name}員工招聘培訓管理");
        }

        public override void Remove(Company company)
        {
            
        }
    }

 

  //財務部類  樹葉節點
    class FinanceDepartment : Company
    {
        public FinanceDepartment(string name) : base(name) { }
        public override void Add(Company company)
        {
           
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-',depth)+Name);
        }

        public override void LineOfDuty()
        {
            Console.WriteLine($"{Name}公司財務收支管理");
        }

        public override void Remove(Company company)
        {
           
        }
    }

 

     static void Main(string[] args)
        {       
            ConcreteCompany root = new ConcreteCompany("北京總公司");
            root.Add(new HRDepartment("總公司人力資源部"));
            root.Add(new FinanceDepartment("總公司財務部"));

            ConcreteCompany comp = new ConcreteCompany("上海華東分公司");
            comp.Add(new HRDepartment("華東分公司人力資源部"));
            comp.Add(new FinanceDepartment("華東分公司財務部"));
            root.Add(comp);
            ConcreteCompany comp1 = new ConcreteCompany("南京分公司");
            comp1.Add(new HRDepartment("南京人力資源部"));
            comp1.Add(new FinanceDepartment("南京財務部"));
            comp.Add(comp1);
            ConcreteCompany comp2 = new ConcreteCompany("杭州分公司");
            comp2.Add(new HRDepartment("杭州人力資源部"));
            comp2.Add(new FinanceDepartment("杭州財務部"));
            comp.Add(comp2);
            Console.WriteLine("\n結構圖");
            root.Display(0);
            Console.WriteLine("\n職責圖");
            root.LineOfDuty();
            Console.Read();
        }

運行結果如下圖

使用場景

1.想表示對象部分-整體層次結構;

2.希望用戶忽略單個對象和組合對象的不同,統一的使用組合結構中的所有對象。

優點

1.高層模塊不需要關心處理的是單個對象還是復合對象;客戶程序可以像處理單個對象一樣處理復合對象,將客戶程序與復合對象容器結構解耦

2.更容易往組合對象中添加新的構件,只需要找父節點即可

缺點:設計更加復雜,使得客戶需要更多時間理清類之間的層次關系

 

關於組合模式的學習就到此結束了,希望能夠幫到你,若有不足,歡迎斧正,感謝您的閱讀。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM