天天看點

設計模式-組合模式和建築者模式詳解

作者:Hu先生Linux背景開發

一. 組合模式

1. 背景

在現實生活中,存在很多“部分-整體”的關系,例如,大學中的部門與學院、總公司中的部門與分公司、學習用品中的書與書包、生活用品中的衣月艮與衣櫃以及廚房中的鍋碗瓢盆等。在軟體開發中也是這樣,例如,檔案系統中的檔案與檔案夾、窗體程式中的簡單控件與容器控件等。對這些簡單對象與複合對象的處理,如果用組合模式來實作會很友善。

2. 定義和特點

(1). 定義:有時又叫作部分-整體模式,它是一種将對象組合成樹狀的層次結構的模式,用來表示“部分-整體”的關系,使使用者對單個對象群組合對象具有一緻的通路性。

(2). 優點:

  A. 組合模式使得用戶端代碼可以一緻地處理單個對象群組合對象,無須關心自己處理的是單個對象,還是組合對象,這簡化了用戶端代碼;

  B. 更容易在組合體内加入新的對象,用戶端不會因為加入了新的對象而更改源代碼,滿足“開閉原則”;

(3). 缺點

  A. 設計較複雜,用戶端需要花更多時間理清類之間的層次關系;

  B. 不容易限制容器中的構件;

  C. 不容易用繼承的方法來增加構件的新功能;

3. 具體實作

(1). 模式結構

  可以自身嵌套結構。

(2). 使用場景

  存儲上下級關系,CEO→技術主管→員工;CEO→銷售主管→員工。

(3). 代碼實操

上下級自身嵌套代碼:

/// <summary>
    /// 員工類
    /// </summary>
    public class Employee
    {
        private string name;
        private string dept;
        private int salary;
        //代表下級子類
        private List<Employee> subordinates;

        //構造函數
        public Employee(string name, string dept, int sal)
        {
            this.name = name;
            this.dept = dept;
            this.salary = sal;
            subordinates = new List<Employee>();
        }

        public void add(Employee e)
        {
            subordinates.Add(e);
        }

        public void remove(Employee e)
        {
            subordinates.Remove(e);
        }

        public List<Employee> getSubordinates()
        {
            return subordinates;
        }

        public string toString()
        {
            return ("Employee :[ Name : " + name
            + ", dept : " + dept + ", salary :"
            + salary + " ]");
        }
    }           

測試代碼:

{
                // 1、樹形機構的場景,使用組合模式
                Employee CEO = new Employee("張三", "CEO", 30000);

                Employee headMarketing = new Employee("李四", "技術經理", 20000);
                Employee headSales = new Employee("王五", "銷售經理", 20000);

                Employee clerk1 = new Employee("趙六", "銷售", 10000);
                Employee clerk2 = new Employee("錢七", "銷售", 10000);

                Employee salesExecutive1 = new Employee("Tony", "技術", 10000);
                Employee salesExecutive2 = new Employee("Mark", "技術", 10000);

                CEO.add(headSales);
                CEO.add(headMarketing);

                headSales.add(clerk1);
                headSales.add(clerk2);

                headMarketing.add(salesExecutive1);
                headMarketing.add(salesExecutive2);

                //列印該組織的所有員工
                Console.WriteLine(CEO.toString());
                foreach (Employee headEmployee in CEO.getSubordinates())
                {
                    Console.WriteLine(headEmployee.toString());
                    foreach (Employee employee in headEmployee.getSubordinates())
                    {
                        Console.WriteLine(employee.toString());
                    }
                }
            }           

運作結果:

設計模式-組合模式和建築者模式詳解

4. 适用場景分析

 A. 在需要表示一個對象整體與部分的層次結構的場合。

 B. 要求對使用者隐藏組合對象與單個對象的不同,使用者可以用統一的接口使用組合結構中的所有對象的場合。

更多C++背景開發技術點知識内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒體,音視訊開發,Linux核心,TCP/IP,協程,DPDK多個進階知識點。

C/C++背景開發架構師免費學習位址:C/C++Linux鏈嶅姟鍣ㄥ紑鍙�/鍚庡彴鏋舵瀯甯堛€愰浂澹版暀鑲層€�-瀛︿範瑙嗛鏁欑▼-鑵捐璇懼爞

【文章福利】另外還整理一些C++背景開發架構師 相關學習資料,面試題,教學視訊,以及學習路線圖,免費分享有需要的可以點選 「連結」 免費領取

設計模式-組合模式和建築者模式詳解

二. 建築者模式

1. 背景

 在軟體開發過程中有時需要建立一個複雜的對象,這個複雜對象通常由多個子部件按一定的步驟組合而成。例如,計算機是由 OPU、主機闆、記憶體、硬碟、顯示卡、機箱、顯示器、鍵盤、滑鼠等部件組裝而成的,采購員不可能自己去組裝計算機,而是将計算機的配置要求告訴計算機銷售公司,計算機銷售公司安排技術人員去組裝計算機,然後再交給要買計算機的采購員。

 生活中這樣的例子很多,如遊戲中的不同角色,其性别、個性、能力、臉型、體型、服裝、發型等特性都有所差異;還有汽車中的方向盤、發動機、車架、輪胎等部件也多種多樣;每封電子郵件的發件人、收件人、主題、内容、附件等内容也各不相同。

 以上所有這些産品都是由多個部件構成的,各個部件可以靈活選擇,但其建立步驟都大同小異。這類産品的建立無法用前面介紹的工廠模式描述,隻有建造者模式可以很好地描述該類産品的建立。

2. 定義和特點

(1). 定義

  指将一個複雜對象的構造與它的表示分離,使同樣的建構過程可以建立不同的表示,這樣的設計模式被稱為建造者模式。它是将一個複雜的對象分解為多個簡單的對象,然後一步一步建構而成。它将變與不變相分離,即産品的組成部分是不變的,但每一部分是可以靈活選擇的。

(2). 優點

 A. 各個具體的建造者互相獨立,有利于系統的擴充。

 B. 用戶端不必知道産品内部組成的細節,便于控制細節風險。

(3). 缺點

 A. 産品的組成部分必須相同,這限制了其使用範圍。

 B. 如果産品的内部變化複雜,該模式會增加很多的建造者類。

(4). 與工廠方法模式的差別

 建造者模式注重零部件的組裝過程,而工廠方模式更注重零部件的建立過程,但兩者可以結合使用。

3. 具體實作

(1). 模式結構

 建造者(Builder)模式由産品、抽象建造者、具體建造者、指揮者等 4 個要素構成。  

 A. 産品角色(Product):它是包含多個組成部件的複雜對象,由具體建造者來建立其各個零部件。

 B. 抽象建造者(Builder):它是一個包含建立産品各個子部件的抽象方法的接口,通常還包含一個傳回複雜産品的方法 getResult()。

 C. 具體建造者(Concrete Builder):實作 Builder 接口,完成複雜産品的各個部件的具體建立方法。

 D. 指揮者(Director):它調用建造者對象中的部件構造與裝配方法完成複雜對象的建立,在指揮者中不涉及具體産品的資訊。

PS:如果建立的産品種類隻有一種,隻需要一個具體建造者,這時可以省略掉抽象建造者,甚至可以省略掉指揮者角色。

結構圖如下:

設計模式-組合模式和建築者模式詳解

(2). 使用場景

 現在要建構自行車,包括核心元件frame、seat、tire,而每個元件可選的材料有多種,自行車的建構順序是固定的,比如按照這個順序:BuidFrame、BuildSeat、BuildTire。這個場景就可以使用建築者模式。

(3). 代碼實操

各種自行車材料代碼:

/// <summary>
    /// 自行車架構
    /// </summary>
    public interface IFrame
    {
        void show();
    }
    /// <summary>
    /// 自行車座椅
    /// </summary>
    public interface ISeat
    {
        void show();
    }
     /// <summary>
    /// 自行車輪胎
    /// </summary>
    public interface ITire
    {
        void show();
    }
    /// <summary>
    /// 合金自行車架構1
    /// </summary>
    public class AlloyFrame1 : IFrame
    {
        public void show()
        {
            Console.WriteLine("我是合金自行車架構1");
        }
    }
    /// <summary>
    /// 合金自行車架構2
    /// </summary>
    public class AlloyFrame2 : IFrame
    {
        public void show()
        {
            Console.WriteLine("我是合金自行車架構2");
        }
    }
    /// <summary>
    /// 真皮座椅1
    /// </summary>
    public class DermisSeat1 : ISeat
    {
        public void show()
        {
            Console.WriteLine("我是真皮座椅1");
        }
    }
    /// <summary>
    /// 真皮座椅2
    /// </summary>
    public class DermisSeat2 : ISeat
    {
        public void show()
        {
            Console.WriteLine("我是真皮座椅2");
        }
    }
     /// <summary>
    /// 結實的輪胎1
    /// </summary>
    public class SolidTire1 : ITire
    {
        public void show()
        {
            Console.WriteLine("我是結實的輪胎1");
        }
    }
    /// <summary>
    /// 結實的輪胎2
    /// </summary>
    public class SolidTire2 : ITire
    {
        public void show()
        {
            Console.WriteLine("我是結實的輪胎2");
        }
    }           

自行車代碼:

/// <summary>
    /// 自行車類
    /// </summary>
    public class Bike
    {
        /// <summary>
        /// 自行車架構
        /// </summary>
        public IFrame frame { set; get; }
        /// <summary>
        /// 自行車座椅
        /// </summary>
        public ISeat seat { set; get; }
        /// <summary>
        /// 自行車 輪胎
        /// </summary>
        public ITire tire { set; get; }

        /// <summary>
        /// 擷取自行車的詳情資訊
        /// </summary>
        public void GetDetils()
        {
            Console.WriteLine("自行車的詳細資訊如下:");
            frame.show();
            seat.show();
            tire.show();
        }
    }           

抽象建築者和具體建築者:

/// <summary>
    /// 抽象建築者類
    /// 如果隻有一個具體的建築者類,則可以省略該抽象建築者類的
    /// </summary>
    public abstract class AbstractBuilder
    {
        public Bike mBike = new Bike();

        public abstract void BuildFrame();

        public abstract void BuildSeat();

        public abstract void BuildTire();

        /// <summary>
        /// 傳回自行車對象
        /// </summary>
        /// <returns></returns>
        public abstract Bike Build();
       

    }
 /// <summary>
    /// 自行車建築者類1
    /// </summary>
    public class BikeBuilder1: AbstractBuilder
    {
        /// <summary>
        /// 建構frame
        /// </summary>
        public override void BuildFrame()
        {
            mBike.frame = new AlloyFrame1();
        }

        /// <summary>
        /// 建構seat
        /// </summary>
        public override void BuildSeat()
        {
            mBike.seat = new DermisSeat1();
        }

        /// <summary>
        /// 建構tire
        /// </summary>
        public override void BuildTire()
        {
            mBike.tire = new SolidTire1();
        }

        /// <summary>
        /// 傳回直行車對象
        /// </summary>
        /// <returns></returns>
        public override Bike Build()
        {
            return mBike;
        }
    }
  /// <summary>
    /// 自行車建築者類2
    /// </summary>
    public class BikeBuilder2 : AbstractBuilder
    {
        /// <summary>
        /// 建構frame
        /// </summary>
        public override void BuildFrame()
        {
            mBike.frame = new AlloyFrame2();
        }

        /// <summary>
        /// 建構seat
        /// </summary>
        public override void BuildSeat()
        {
            mBike.seat = new DermisSeat2();
        }

        /// <summary>
        /// 建構tire
        /// </summary>
        public override void BuildTire()
        {
            mBike.tire = new SolidTire2();
        }

        /// <summary>
        /// 傳回直行車對象
        /// </summary>
        /// <returns></returns>
        public override Bike Build()
        {
            return mBike;
        }
    }

           

指揮者:

/// <summary>
    /// 指揮者
    /// 調用建造者中的方法完成複雜對象的建立
    /// 如果隻有一個建築者的話,可以省略該指揮者的角色
    /// </summary>
    public class BikeDirector
    {
        private AbstractBuilder _builder;
        public BikeDirector(AbstractBuilder builder)
        {
            this._builder = builder;
        }
        /// <summary>
        /// Bike的建構群組裝
        /// </summary>
        /// <returns></returns>
        public Bike CreateBike()
        {
            _builder.BuildFrame();
            _builder.BuildSeat();
            _builder.BuildTire();

            return _builder.Build();
        }
    }           

測試代碼:

//1.普通模式
                {
                    Console.WriteLine("-------------------下面是普通模式建構自行車-------------------------");
                    //1. 建構自行車
                    Bike b = new Bike();
                    b.frame = new AlloyFrame1();
                    b.seat = new DermisSeat2();
                    b.tire = new SolidTire1();

                    //2. 輸出自行車資訊
                    b.GetDetils();
                }

                //2. 使用建築者模式
                {
                    Console.WriteLine("-------------------下面是使用建築者模式建構自行車-------------------------");
                    //1. 建構建築者
                    BikeBuilder1 builder = new BikeBuilder1();
                    builder.BuildFrame();
                    builder.BuildSeat();
                    builder.BuildTire();
                    //2. 建構自行車
                    Bike bike = builder.Build();
                    //3. 輸出自行車的資訊
                    bike.GetDetils();
                }

                //3. 引入抽象建築者父類
                {
                    Console.WriteLine("-------------------下面是 引入抽象建築者父類 建構自行車-------------------------");
                    //1. 建構建築者1
                    AbstractBuilder builder = new BikeBuilder1();
                    builder.BuildFrame();
                    builder.BuildSeat();
                    builder.BuildTire();
                    //2. 建構自行車
                    Bike bike = builder.Build();
                    //3. 輸出自行車的資訊
                    bike.GetDetils();

                    //1. 建構建築者2
                    AbstractBuilder builder2 = new BikeBuilder2();
                    builder2.BuildFrame();
                    builder2.BuildSeat();
                    builder2.BuildTire();
                    //2. 建構自行車
                    Bike bike2 = builder2.Build();
                    //3. 輸出自行車的資訊
                    bike2.GetDetils();
                }

                //4. 引入指揮者
                {
                    Console.WriteLine("-------------------下面是 引入指揮者 建構自行車-------------------------");
                    //指揮者1
                    BikeDirector dirctor1 = new BikeDirector(new BikeBuilder1());
                    Bike bike1 = dirctor1.CreateBike();
                    bike1.GetDetils();

                    //指揮者2
                    BikeDirector dirctor2 = new BikeDirector(new BikeBuilder2());
                    Bike bike2 = dirctor2.CreateBike();
                    bike2.GetDetils();
                }

           

運作效果:

設計模式-組合模式和建築者模式詳解

4. 适用場景分析

 建造者(Builder)模式建立的是複雜對象,其産品的各個部分經常面臨着劇烈的變化,但将它們組合在一起的算法卻相對穩定,是以它通常在以下場合使用。

 A. 建立的對象較複雜,由多個部件構成,各部件面臨着複雜的變化,但構件間的建造順序是穩定的。

 B. 建立複雜對象的算法獨立于該對象的組成部分以及它們的裝配方式,即産品的建構過程和最終的表示是獨立的。

原文連結:https://www.cnblogs.com/yaopengfei/p/13462519.html

繼續閱讀