1. 程式人生 > >用心理解設計模式——建造者模式 (Builder Pattern)

用心理解設計模式——建造者模式 (Builder Pattern)

前置文章: 用心理解設計模式——設計模式的原則 

設計模式相關程式碼已統一放至 我的 Github

 

一、定義

  建立型模式之一。

  Separate the construction of a complex object from its representation so that the same construction process can create different representations

(將複雜物件的構造與它的表示分離,以便相同的構造過程可以創建出不同的表示。)

二、結構解析

  建造者模式的一般結構有四種角色:產品、抽象建造者、具體建造者、導演。

  產品, 複雜的、可拆卸組合的物件。一般,它的內部對產品部件進行了固定規則的有限組織(組織部件演算法的不變部分)。

  抽象建造者,負責定義產品各個部件的建造方法介面。

  具體建造者,負責實際建造產品的各個部件,只建造不組織

  導演,在產品內部組織部件演算法的基礎之上,進行種類、數量和順序的組織(組織部件演算法的可變部分),只組織不建造

三、評價

  建造者模式,NRatel仔細研究了好幾天,看懂後才發現其異常精妙!

  它通過讓具體建造者重寫抽象建造者定義的產品的各個部件的建造方法,使產品產生部件種類多樣性;

  又通過導演對體建造者建造出來的的產品的各個部件進行組織,使產品產生部件的種類組成(進行有限選擇)、數量、順序多樣性。

  這樣一縱一橫(如下圖,縱向重寫,橫向組織),使產品相同的構造過程可以創建出不同的表示。

四、實現

using System.Collections.Generic;

namespace Builder
{
    //輔助測試Part類
    public class Part
    {
        public string partName;
        public Part(string partName) { this.partName = partName; }
    }

    //產品類
    public class Product
    {
        public string productName;
        //產品類中對Part有其固定的組織方法,是組織部件的演算法中的不變部分。 如此處,產品名由部件名按傳入順序組成。
        //Director中也會對Part進行組織,是組織部件的演算法中的變化部分。如此例,組織了部件的種類、數量、和傳入順序。
        public Product(List<Part> partList)
        {
            productName = "";
            partList.ForEach((Part p) => {
                productName += p.partName;
            });
        }
    }

    //抽象建造者類
    public abstract class Builder
    {
        public abstract Part BuildPart1();
        public abstract Part BuildPart2();
        public abstract Part BuildPart3();
    }

    //具體建造者類
    public class ConcreteBuilderX : Builder
    {
        public override Part BuildPart1()
        {
            return new Part("1X");
        }

        public override Part BuildPart2()
        {
            return new Part("2X");
        }
        public override Part BuildPart3()
        {
            return new Part("3X");
        }
    }

    //具體建造者類
    public class ConcreteBuilderY : Builder
    {
        public override Part BuildPart1()
        {
            return new Part("1Y");
        }

        public override Part BuildPart2()
        {
            return new Part("2Y");
        }
        public override Part BuildPart3()
        {
            return new Part("3Y");
        }
    }

    //導演類
    public class Director
    {
        //例:建造某個產品A的方法。
        public Product ConstructA()
        {
            //建造產品A 需要 ConcreteBuilderX 中提供的產品部件種類。
            //通過選擇不同的ConcreteBuilder,使產品產生部件種類多樣性。
            Builder builder = new ConcreteBuilderX();
            //產品A需要 只需要兩個第三部分和一個第一部分,並且按331的順序傳入。
            //通過組織,使產品產生部件的種類組成(進行有限選擇)、數量、順序多樣性。
            Part part3 = builder.BuildPart3();
            Part part3s = builder.BuildPart3();
            Part part1 = builder.BuildPart1();

            List<Part> parts = new List<Part>();
            parts.Add(part3);
            parts.Add(part3s);
            parts.Add(part1);
            //傳入構造引數建立A
            return new Product(parts);
        }

        //例:建造某個產品B的方法。
        public Product ConstructB()
        {
            //建造產品B 需要 ConcreteBuilderY 中提供的產品部件種類。
            Builder builder = new ConcreteBuilderY();
            //產品B需要 只需要三個第三部分和一個第二部分、一個第三部分,並且按11123的順序傳入。
            Part part1 = builder.BuildPart1();
            Part part1s = builder.BuildPart1();
            Part part1ss = builder.BuildPart1();
            Part part2 = builder.BuildPart2();
            Part part3 = builder.BuildPart3();

            List<Part> parts = new List<Part>();
            parts.Add(part1);
            parts.Add(part1s);
            parts.Add(part1ss);
            parts.Add(part2);
            parts.Add(part3);
            return new Product(parts);
        }
    }

    //客戶類
    public class Client
    {
        static public void Main()
        {
            Director director = new Director();
            Product productA = director.ConstructA();
            //Debug.Log(productA.productName); 
            
            Product productB = director.ConstructB();
            //Debug.Log(productB.productName); 
        }
    }
}