設計模式複習(五)-------建造者模式

1.定義

建造者模式可以將部件本身和它們的組裝過程分開,關注如何一步步創建一個包含多個組成部分的複雜對象,用戶只需要指定複雜對象的類型即可得到該對象,而無須知道其內部的具體構造細節

將一個複雜對象的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。
—《設計模式》GoF

  • 在軟件系統中,有時候面臨着“一個複雜對象”的創建工作,複雜對象由各個部分的子對象用一定的算法構成;
    由於需求的變化,複雜對象的各個部分經常面臨着劇烈的變化,但是將它們組合在一起的算法卻相對穩定。

  • 如何應對這種變化?

  • 如何提供一種“封裝機制”來隔離出“複雜對象的各個部分”的變化,從而保持系統中的“穩定構建算法”不隨着需求改變而改變?

  • 對象相當於一個待建造的產品,而對象的屬性相當於產品的零件,建造產品的過程就是組合零件的過程:由於過程很複雜

  • 過程:客戶端負責創建指導者和具體建造者對象。然後,客戶把具體建造者對象交給指導者。客戶一聲令下,指導者操縱建造者開始創建產品。當產品創建完成後,建造者把產品返還給客戶端。

2.結構

  • 建造者(Builder)角色:給出一個抽象接口,以規範產品對象的各個組成成分的建造。一般而言,此接口獨立於應用程序的商業邏輯。模式中直接創建產品對象的是具體建造者(ConcreteBuilder)角色。具體建造者類必須實現這個接口所要求的方法:一個是建造方法,另一個是結果返還方法。
  • 具體建造者(Concrete Builder)角色:擔任這個角色的是與應用程序緊密相關的類,它們在應用程序調用下創建產品實例。這個角色主要完成的任務包括:
    實現Builder角色提供的接口,定義產品對象,一步一步(零件)完成創建產品實例的過程。
    在建造過程完成後,提供產品的實例(完整產品)。
  • 指導者(Director)角色:擔任這個角色的類調用具體建造者角色以創建產品對象。指導者並沒有產品類的具體知識,真正擁有產品類的具體知識的是具體建造者對象。
  • 產品(Product)角色:產品便是建造中的複雜對象。
    指導者角色是與客戶端打交道的角色。指導者將客戶端創建產品的請求劃分爲對各個零件的建造請求,再將這些請求委派給具體建造者內部的具體方法。具體建造者角色是做具體建造工作的,但卻不爲客戶端所知。

在這裏插入圖片描述

具體的構建者可以有多個,它們都繼承自Builder父類(或實現這個接口)

3.實例

這個得好好寫寫,上課走神了…

遊戲中構建一座房子時,房子的構成和構建步驟通常是穩定不變的,但是房子的風格要經常變化,因此這樣的的房子的構建可以選用建造者模式。
(示例–GameHouseBuilder)
Builder模式主要用於“分步驟構建一個複雜的對象”。在這其中“分步驟”是一個穩定的算法(即Director,如上面例子中的GameManager),而複雜對象的各個部分(即ConcreteBuilder)則經常變化。
AbstractFactory模式解決“系列對象”的需求變化,Builder模式解決“對象部分”的需求變化。Builder模式通常和Composite(組合)模式組合使用。

老師給的源碼是用C#寫的不帶配置文件的,我再添加兩句

項目工程結構:

在這裏插入圖片描述

/*
抽象建造者Builder
*/
namespace GameHouseBuilder
{
    //抽象建造者,規定構建的基本構件和搭建過程
    public abstract class Builder 
    {
        //房屋的部分構造器
        public abstract void BuildWall();
        public abstract void BuildDoor();
        public abstract void BuildWindow();
        public abstract void BuildFloor();
        public abstract void BuildCeiling();

        //獲取構建好的房屋--零件組合過程隱含於其中--此過程應該穩定
        public abstract House GetHouse();
    }
}

/*
	1.具體建造者ClassicalHouseBuilder,還有一個具體構建者代碼不貼了
	2.在實際項目中,下面的打印語句實際上是爲對象添加屬性,然後給客戶端返回一個按要求封裝好的對象;
	3.按照建造者模式的定義,客戶端指導建造者只是下達一個建造命令,即可得到一個封裝好的對象,客戶端對建造者中的具體知識並不瞭解,具體的構件過程由指導者指導
	4.另外因爲沒有具體的業務邏輯要求,實體類House的屬性沒有被定義
*/
namespace GameHouseBuilder
{
    /// <summary>
    /// 具體的創建者類
    /// </summary>
    public class ClassicalHouseBuilder : Builder 
    {
        private House house=null; //要構建的具體的產品對象

        //房屋的部分構造器
        public override void BuildWall(){
            Console.WriteLine("構建古典型的牆");
        }
        public override void BuildDoor(){
            Console.WriteLine("構建古典型的門");
        }
        public override void BuildWindow(){
            Console.WriteLine("構建古典型的窗戶");
        }
        public override void BuildFloor(){
            Console.WriteLine("構建古典型的地板");
        }
        public override void BuildCeiling(){
            Console.WriteLine("構建古典型的天花板");
        }

        //搭建房屋,然後獲取構建好的房屋
        public override House GetHouse() {
            //具體組裝......

            Console.WriteLine("\n返回建造好的古典型的房屋\n");
            return house;
        }
    }
}
namespace GameHouseBuilder
{
    /// <summary>
    /// 建造者模式中的Director,負責管理創建對象的具體過程
    /// </summary>
    public class GameManager
    {
        public static House CreateHouse(Builder builder) //biulder爲具體的創建者對象
        {
            //零件的構建過程--以下的構建過程相對穩定, 否則不能使用建造者模式
            builder.BuildWall();
            builder.BuildWall();
            builder.BuildWall();
            builder.BuildWall();

            builder.BuildDoor();
            builder.BuildDoor();

            builder.BuildWindow();
            builder.BuildWindow();

            builder.BuildCeiling();

            builder.BuildFloor();
            //零件的構建過程--如果以上構建過程不穩定,則Builder模式就不適用了

            return builder.GetHouse(); //創建完畢各個部分後, 組裝--〉返回完整的對象
        }
    }
}

/*
	反射機制需要用到下面兩個類庫,不要忘了引入;
	具體的反射實現細節跟上午用Java做的差不多,也是讀取配置文件->拼出全類名->利用反射機制創建對象
	這樣就做到了完全解耦,以後如果需求再變化,比如加一種新的房屋樣式,原來的源碼一點也不用改。
*/
using System.Reflection;
using System.Configuration;
namespace GameHouseBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            Builder builder;
            string builderType = ConfigurationSettings.AppSettings["builder"];
            builder = (Builder)Assembly.Load("GameHouseBuilder").CreateInstance("GameHouseBuilder." + builderType);
            //構建具體構造器對象
            //也可以利用反射機制避免更改此處代碼
            //Builder builder = new ClassicalHouseBuilder();
            //Builder builder = new RomanticHouseBuilder();

            //客戶程序只需要調用Director的方法就可以方便的構建對象,更改對象類型只需要改動具體構造器類型
            House house = GameManager.CreateHouse(builder);

            //利用House對象作其他操作
            //house.xxx();

            Console.ReadLine();
        }
    }
}

4.優點

  • 客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。
  • 每一個具體建造者都相對獨立,與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,擴展方便,符合開放/封閉原則;
  • 可以更加精細地控制產品的創建過程。

5.缺點

  • 建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,不適合使用建造者模式,因此其使用範圍受到一定的限制;

    分步驟構建算法(包括零部件的構建與組合,即Director和Builder)如果不穩定,則不適合;

  • 如果產品的內部變化複雜,可能會需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大,增加了系統的理解難度和運行成本。

6.建造者模式的適用環境

  • 需要生成的產品對象有複雜的內部結構,這些產品對象通常包含多個成員變量;
  • 需要生成的產品對象的屬性相互依賴,需要指定其生成順序;

下一輪複習的時候做做這個題

4、計算機組裝工廠可以將CPU、內存、硬盤、主機、顯示器等硬件設備組裝在一起構成一臺完整的計算機,且構成的計算機可以是筆記本,也可以是臺式機,還可以是不提供顯示器的服務器主機。對於用戶而言,無須關心計算機的組成設備和組裝過程,工廠返回給用戶的。是完整的計算機對象,使用建造者模式實現計算機組裝過程,要求繪製類圖並使用C#代碼編程模擬實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章