C#設計模式系列:建造者模式(Builder)

libingql發表於2014-03-30

1、建造者模式簡介

1.1>、定義

  建造者模式(Builder)將複雜的構建與其表示相分離,使得同樣的構建過程可以建立不同的表示。

1.2>、使用頻率

   中低

1.3>、原型模式應用

  在軟體系統中,有時候面臨一個複雜物件的建立工作,該物件通常由各個部分子物件用一定的演算法構成,或者按一定的步驟組合而成;這些演算法和步驟是穩定的,而構成這個物件的子物件卻經常由於需求的變化而不斷變化。

  生活中的例子,要組裝一臺電腦,它的組裝過程基本是不變的,都可以由主機板、CPU、記憶體等按照某個穩定方式組合而成。然而主機板、CPU、記憶體等零件本身都是可能多變的。將記憶體等這種易變的零件與電腦的其他部件分離,實現解耦合,則可以輕鬆實現電腦不斷升級。

2、建造者模式結構

2.1>、結構圖

2.2>、參與者

  建造者模式參與者:

  ◊ Builder:為建立一個Product物件的各個部件指定抽象介面;

  ◊ ConcreteBuilder

    ° 實現Builder的介面以構造和裝配該產品的各個部件

    ° 定義並明確它所建立的表示

    ° 提供一個檢索Product的介面

  ◊ Director:構造一個使用Builder介面的物件;

  ◊ Product

    ° 表示被構造的複雜物件。ConcreteBuilder建立該產品的內部表示並定義它的裝配過程

    ° 包含定義組成部件的類,包括將這些部件裝配成最終產品的介面

  在建造者模式中,Director規定了建立一個物件所需要的步驟和次序,Builder則提供了一些列完成這些步驟的方法,ConcreteBuilder給出了這些方法的具體實現,是物件的直接建立者。

3、建造者模式結構實現

  Product.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Structural
{
    public class Product
    {
        private List<string> _parts = new List<string>();

        public void Add(string part)
        {
            _parts.Add(part);
        }

        public void Show()
        {
            Console.WriteLine("Product Parts");
            foreach (string part in _parts)
            {
                Console.WriteLine(part);
            }
        }
    }
}

  Builder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Structural
{
    public abstract class Builder
    {
        public abstract void BuildPartA();
        public abstract void BuildPartB();
        public abstract Product GetResult();
    }
}

  ConcreteBuilder1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Structural
{
    public class ConcreteBuilder1 : Builder
    {
        private Product _product = new Product();

        public override void BuildPartA()
        {
            _product.Add("PartA");
        }

        public override void BuildPartB()
        {
            _product.Add("PartB");
        }

        public override Product GetResult()
        {
            return _product;
        }
    }
}

  ConcreteBuilder2.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Structural
{
    public class ConcreteBuilder2 : Builder
    {
        private Product _product = new Product();

        public override void BuildPartA()
        {
            _product.Add("PartX");
        }

        public override void BuildPartB()
        {
            _product.Add("PartY");
        }

        public override Product GetResult()
        {
            return _product;
        }
    }
}

  Director.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Structural
{
    public class Director
    {
        /// <summary>
        /// Builder uses a complex series of steps
        /// </summary>
        public void Construct(Builder builder)
        {
            builder.BuildPartA();
            builder.BuildPartB();
        }
    }
}

  Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DesignPatterns.BuilderPattern.Structural;

namespace DesignPatterns.BuilderPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create director and builders
            Director director = new Director();

            Builder b1 = new ConcreteBuilder1();
            Builder b2 = new ConcreteBuilder2();
            
            // Construct two products
            director.Construct(b1);
            Product p1 = b1.GetResult();
            p1.Show();

            director.Construct(b2);
            Product p2 = b2.GetResult();
            p2.Show();
        }
    }
}

  執行輸出:

Product Parts
PartA
PartB
Product Parts
PartX
PartY
請按任意鍵繼續. . .

4、建造者模式實踐應用

  Vehicle.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Practical
{
    /// <summary>
    /// The 'Product' class
    /// </summary>
    public class Vehicle
    {
        private string _vehicleType;
        private Dictionary<string, string> _parts = new Dictionary<string, string>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Vehicle(string vehicleType)
        {
            this._vehicleType = vehicleType;
        }

        /// <summary>
        /// Indexer
        /// </summary>
        public string this[string key]
        {
            get { return _parts[key]; }
            set { _parts[key] = value; }
        }

        public void Show()
        {
            Console.WriteLine("\n---------------------------");
            Console.WriteLine("Vehicle Type: {0}", _vehicleType);
            Console.WriteLine(" Frame : {0}", _parts["frame"]);
            Console.WriteLine(" Engine : {0}", _parts["engine"]);
            Console.WriteLine(" #Wheels: {0}", _parts["wheels"]);
            Console.WriteLine(" #Doors : {0}", _parts["doors"]);
        }
    }
}

  VehicleBuilder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Practical
{
    /// <summary>
    /// The 'Builder' abstract class
    /// </summary>
    public abstract class VehicleBuilder
    {
        protected Vehicle vehicle;

        // Gets vehicle instance
        public Vehicle Vehicle
        {
            get { return vehicle; }
        }

        // Abstract build methods
        public abstract void BuildFrame();
        public abstract void BuildEngine();
        public abstract void BuildWheels();
        public abstract void BuildDoors();
    }
}

  MotorCycleBuilder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Practical
{
    public class MotorCycleBuilder : VehicleBuilder
    {
        public MotorCycleBuilder()
        {
            vehicle = new Vehicle("MotorCycle");
        }

        public override void BuildFrame()
        {
            vehicle["frame"] = "MotorCycle Frame";
        }

        public override void BuildEngine()
        {
            vehicle["engine"] = "500 cc";
        }

        public override void BuildWheels()
        {
            vehicle["wheels"] = "2";
        }

        public override void BuildDoors()
        {
            vehicle["doors"] = "0";
        }
    }
}

  CarBuilder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Practical
{
    public class CarBuilder : VehicleBuilder
    {
        public CarBuilder()
        {
            vehicle = new Vehicle("Car");
        }

        public override void BuildFrame()
        {
            vehicle["frame"] = "Car Frame";
        }

        public override void BuildEngine()
        {
            vehicle["engine"] = "2500 cc";
        }

        public override void BuildWheels()
        {
            vehicle["wheels"] = "4";
        }

        public override void BuildDoors()
        {
            vehicle["doors"] = "4";
        }
    }
}

  ScooterBuilder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Practical
{
    public class ScooterBuilder : VehicleBuilder
    {
        public ScooterBuilder()
        {
            vehicle = new Vehicle("Scooter");
        }

        public override void BuildFrame()
        {
            vehicle["frame"] = "Scooter Frame";
        }

        public override void BuildEngine()
        {
            vehicle["engine"] = "50 cc";
        }

        public override void BuildWheels()
        {
            vehicle["wheels"] = "2";
        }

        public override void BuildDoors()
        {
            vehicle["doors"] = "0";
        }
    }
}

  Shop.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.BuilderPattern.Practical
{
    public class Shop
    {
        public void Construct(VehicleBuilder vehicleBuilder)
        {
            vehicleBuilder.BuildFrame();
            vehicleBuilder.BuildEngine();
            vehicleBuilder.BuildWheels();
            vehicleBuilder.BuildDoors();
        }
    }
}

  Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DesignPatterns.BuilderPattern.Practical;

namespace DesignPatterns.BuilderPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            VehicleBuilder builder;
            // Create shop with vehicle builders
            Shop shop = new Shop();

            // Construct and display vehicles
            builder = new ScooterBuilder();
            shop.Construct(builder);
            builder.Vehicle.Show();

            builder = new CarBuilder();
            shop.Construct(builder);
            builder.Vehicle.Show();

            builder = new MotorCycleBuilder();
            shop.Construct(builder);
            builder.Vehicle.Show();
        }
    }
}

  執行輸出:

---------------------------
Vehicle Type: Scooter
 Frame : Scooter Frame
 Engine : 50 cc
 #Wheels: 2
 #Doors : 0

---------------------------
Vehicle Type: Car
 Frame : Car Frame
 Engine : 2500 cc
 #Wheels: 4
 #Doors : 4

---------------------------
Vehicle Type: MotorCycle
 Frame : MotorCycle Frame
 Engine : 500 cc
 #Wheels: 2
 #Doors : 0
請按任意鍵繼續. . .

5、建造者模式應用分析

  建造者模式適用情形:

  ◊ 需要生成的產品物件有複雜的內部結構

  ◊ 需要生成的產品物件的屬性相互依賴,建造者模式可以強迫生成順序

  ◊ 在物件建立過程中會使用到系統中的一些其他物件,這些物件在產品物件的建立過程中不易得到

  建造者模式特點:

  ◊ 建造者模式的使用使得產品的內部表物件可以獨立地變化。使用建造者模式可以使客戶不必知道產品內部組成的細節

  ◊ 每一個Builder都相對獨立,而與其他Builder無關

  ◊ 可使對構造過程更加精細控制

  ◊ 將構建程式碼和表示程式碼分開

  ◊ 建造者模式的缺點在於難於應付分步驟構建演算法的需求變動

相關文章