C#設計模式學習筆記:(4)建造者模式

来源:https://www.cnblogs.com/atomy/archive/2020/01/14/12191882.html
-Advertisement-
Play Games

本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,記錄一下學習過程以備後續查用。 一、引言 在現實生活中,我們經常會遇到一些構成比較複雜的物品。比如電腦,是由CPU、主板、記憶體條、硬碟、顯卡、機箱等組裝而成的。手機也是複雜物品, 由主板 ...


    本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,記錄一下學習過程以備後續查用。

    一、引言

    在現實生活中,我們經常會遇到一些構成比較複雜的物品。比如電腦,是由CPU、主板、記憶體條、硬碟、顯卡、機箱等組裝而成的。手機也是複雜物品,

由主板、各種晶元、RAM、ROM、攝像頭等部件組成。但是無論是電腦還是手機,它們的組裝過程是固定的。拿手機來說,組裝流水線是固定的、不變的,

但是把不同的主板和其它組件組裝在一起就會生產出不同型號的手機。那麼在軟體系統中是不是也會存在這樣的對象呢?答案是肯定的。在軟體系統中我們

也會遇到類似的複雜對象,並且這個複雜對象的各個部分按照一定的演算法組合在一起,此時該對象的創建工作就可以使用Builder模式了,下麵讓我們詳細看

看這個模式吧。

    二、建造者模式介紹

    建造者模式(也叫生成器模式):英文名稱--Builder Pattern;分類--創建型。

    2.1、動機(Motivate)

    在軟體系統中,有時候面臨著“一個複雜對象”的創建工作,其通常由各個部分的子對象用一定的演算法構成。由於需求的變化,這個複雜對象的各個部分經

常面臨著劇烈的變化,但是將它們組合在一起的演算法卻相對穩定。如何應對這種變化?如何提供一種“封裝機制”來隔離出“複雜對象的各個部分”的變化,從

而保持系統中的“穩定構建演算法”不隨著需求改變而改變?

    2.2、意圖(Intent)

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

    2.3、結構圖(Structure)

    2.4、模式的組成

    1)抽象建造者角色(Builder):為創建一個Product對象的各個部件指定抽象介面,以規範產品對象的各個組成部分的建造。一般而言,此角色規定要實

現複雜對象的哪些部件的創建,並不涉及具體的對象部件的創建。

    2)具體建造者(ConcreteBuilder)

    I、實現Builder的介面以構造和裝配該產品的各個部件,即實現抽象建造者角色Builder的方法。

    II、定義並明確它所創建的表示,即針對不同的商業邏輯,具體化複雜對象的各個部分的創建。

    III、提供一個檢索產品的介面。

    IV、構造一個使用Builder介面的對象,即在指導者的調用下創建產品實例。

    3)指導者(Director):調用具體建造者角色以創建產品對象的各個部分。指導者並沒有涉及具體產品類的信息,真正擁有具體產品的信息是具體建造者

對象。它只負責保證對象各部分完整創建或按某種順序創建。

    4)產品角色(Product):建造中的複雜對象。它要包含那些定義組件的類,包括將這些組件裝配成產品的介面。

    2.5 建造者模式的代碼實現

    現在人們生活水平都提高了,家家都有了家庭轎車,那今天我們就以汽車組裝為例來說明Builder模式的實現。

    class Program
    {
        /// <summary>
        /// 小轎車類
        /// </summary>
        public sealed class SaloonCar
        {
            //小轎車部件集合
            private IList<string> parts = new List<string>();

            //把單個部件添加到小轎車部件集合中
            public void Add(string part)
            {
                parts.Add(part);
            }

            public void Show()
            {
                Console.WriteLine("小轎車開始組裝.......");
                foreach (string part in parts)
                {
                    Console.WriteLine("部件[" + part + "]已組裝。");
                }

                Console.WriteLine("小轎車組裝完畢。");
            }
        }

        /// <summary>
        /// 抽象建造者,它定義了要創建什麼部件和最後創建的結果,但是不是組裝的的類型,切記。
        /// </summary>
        public abstract class Builder
        {
            //創建車門
            public abstract void BuildSaloonCarDoor();
            //創建車輪
            public abstract void BuildSaloonCarWheel();
            //創建車引擎
            public abstract void BuildSaloonCarEngine();
            //獲得組裝好的小轎車
            public abstract SaloonCar GetSaloonCar();
        }

        /// <summary>
        /// 具體創建者,具體車型的創建者,例如:別克。
        /// </summary>
        public sealed class BuickBuilder : Builder
        {
            SaloonCar buickCar = new SaloonCar();
            public override void BuildSaloonCarDoor()
            {
                buickCar.Add("Buick's door");
            }

            public override void BuildSaloonCarWheel()
            {
                buickCar.Add("Buick's wheel");
            }

            public override void BuildSaloonCarEngine()
            {
                buickCar.Add("Buick's engine");
            }

            public override SaloonCar GetSaloonCar()
            {
                return buickCar;
            }
        }

        /// <summary>
        /// 具體創建者,具體車型的創建者,例如:奧迪
        /// </summary>
        public sealed class AoDiBuilder : Builder
        {
            SaloonCar aoDiCar = new SaloonCar();
            public override void BuildSaloonCarDoor()
            {
                aoDiCar.Add("Aodi's door");
            }

            public override void BuildSaloonCarWheel()
            {
                aoDiCar.Add("Aodi's wheel");
            }

            public override void BuildSaloonCarEngine()
            {
                aoDiCar.Add("Aodi's engine");
            }

            public override SaloonCar GetSaloonCar()
            {
                return aoDiCar;
            }
        }

        /// <summary>
        /// 這個類型才是組裝的
        /// Construct方法裡面的實現就是創建複雜對象固定演算法的實現,該演算法是固定的或者說是相對穩定的。
        /// 這個人當然就是老闆了,也就是建造者模式中的指揮者。
        /// </summary>
        public class Director
        {
            //組裝汽車
            public void Construct(Builder builder)
            {
                builder.BuildSaloonCarDoor();
                builder.BuildSaloonCarWheel();
                builder.BuildSaloonCarEngine();
            }
        }

        static void Main(string[] args)
        {
            #region 建造者模式
            Director director = new Director();
            Builder buickBuilder = new BuickBuilder();
            Builder aoDiBuilder = new AoDiBuilder();

            //組裝別克小轎車
            director.Construct(buickBuilder);
            SaloonCar buickCar = buickBuilder.GetSaloonCar();
            buickCar.Show();

            Console.WriteLine();

            //組裝奧迪小轎車
            director.Construct(aoDiBuilder);
            SaloonCar aoDiCar = aoDiBuilder.GetSaloonCar();
            aoDiCar.Show();

            Console.Read();
            #endregion
        }
    }
View Code

    運行結果如下:

    三、建造者模式的實現要點

    在建造者模式中,指揮者是直接與客戶端打交道的。指揮者將客戶端創建產品的請求轉換為對各個部件的建造請求,再將這些請求委派給具體的建造者角

色,而具體的建造者角色是完成具體產品的構建工作的,卻不為客戶所知道。

    建造者模式主要用於“分步驟來構建一個複雜的對象”,其中“分步驟”是一個固定的組合過程,而複雜對象的各個部分是經常變化的。 產品不需要抽象類

因為建造者模式創建出來的最終產品可能差異很大,所以不大可能提煉出一個抽象產品類。 在前面文章中介紹的抽象工廠模式解決了“多系列產品”的需求變

化,而建造者模式解決的是 “產品部分” 的需要變化。 由於建造者隱藏了具體產品的組裝過程,所以要改變一個產品的內部表示,只需要再實現一個具體的

建造者就可以了,從而能很好地應對產品組成部件的需求變化。

    3.1、建造者模式的優點

    1)使用建造者模式可以使客戶端不必知道產品內部組成的細節。

    2)具體的建造者類之間是相互獨立的,容易擴展。

    3)由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模塊產生任何影響。

    3.2、建造者模式的缺點

    1)產生多餘的Build對象以及Dirextor類。

    3.3、創建者模式的使用場景

    1)當創建複雜對象的演算法應該獨立於該對象的組成部分以及它們的裝配方式時。

    2)相同的方法,不同的執行順序,產生不同的事件結果時。

    3)多個部件或零件,都可以裝配到一個對象中,但是產生的運行結果又不相同時。

    4)產品類非常複雜,或者產品類中的調用順序不同產生了不同的效能。

    5)創建一些複雜的對象時,這些對象的內部組成構件間的建造順序是穩定的,但是對象的內部組成構件面臨著複雜的變化。

    四、.NET中建造者模式的實現

    微軟的類庫裡面大量使用了設計模式,如果要想學習設計模式,仔細看看微軟的類庫是很有幫助的。今天的設計模式在FCL裡面也有實現,該類型的名字

是System.Text.StringBuilder(存在於mscorlib.dll程式集中),它就是一個建造者模式的實現,從名稱也可以看出來。不過它的實現屬於建造者模式的演化,此時

的建造者模式沒有指揮者角色和抽象建造者角色,StringBuilder類既扮演著具體建造者的角色,也同時扮演了指揮者和抽象建造者的角色。

    StringBuilder類扮演著建造string對象的具體建造者角色,其中的ToString()方法用來返回具體產品給客戶端(相當於上面代碼中GetSaloonCar方法)。其中

Append方法用來創建產品的組件(相當於上面代碼中Add方法),因為string對象中每個組件都是字元,所以也就不需要指揮者角色的代碼(如上面代碼中的

Construct方法),Append方法也充當了指揮者Construct方法的作用。

    五、總結

    需要重申的是,學習設計模式不能死學,就像StringBuilder一樣,他和Gof23種設計模式中定義的情形有很大的不同,但是它也是Builder模式,因為它要解決

的問題和使用場景是吻合的。我們寫代碼的時候,不要太居於形式,要看使用的契機和模式是否吻合,根據具體的情況我們的模式也會發生變化。當我們看得越

多也寫得越多的時候,變化就越自然了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • CPU的組成 CPU是由運算器(信息處理)、控制器(控制器件工作)、寄存器(信息存儲)等器件組成,他們之間通過匯流排相連。 通用寄存器 通用寄存器時用於存放一般性數據的,以8086 CPU為例,8086 CPU所有的寄存器都是16位的,8086 CPU中的通用寄存器有AX、BX、CX、DX。為了相容上 ...
  • 1.使用“\d+”匹配全數字 代碼: 1 import re 2 3 zen = "Arizona 479, 501, 870. Carlifornia 209, 213, 650." 4 5 m = re.findall("\d+", zen) 6 7 print(m) 結果: ['479', ' ...
  • hibernate中的延遲載入(lazyload)分屬性的延遲載入和關係的延遲載入 屬性的延遲載入: 當使用load的方式來獲取對象的時候,只有訪問了這個對象的屬性,hibernate才會到資料庫中進行查詢。否則不會訪問資料庫 Load的載入方式:1、Load採用延遲載入的方式,hibernate的 ...
  • Web服務 Web服務可以讓你在HTTP協議的基礎上通過XML或者JSON來交換信息。如果你想知道上海的天氣預報、中國石油的股價或者淘寶商家的一個商品信息,你可以編寫一段簡短的代碼,通過抓取這些信息然後通過標準的介面開放出來,就如同你調用一個本地函數並返回一個值。 Web服務背後的關鍵在於平臺的無關 ...
  • AbstractCollection介紹 AbstractCollection抽象類是Collection的基本實現,其實現了Collection中的大部分方法,可以通過繼承此抽象類以最少的代價來自定義Collection; 如果要定義一個不可變Collection,只需要繼承此類,並實現itera ...
  • 這裡沒有線程 原文地址: "https://blog.stephencleary.com/2013/11/there is no thread.html" 前言 我是在看 C 8.0 新特性非同步流時在評論里看到這篇文章的,閱讀之後發現這篇文章乾貨滿滿,作者解釋的非常清晰,裡面的本質分析內容在《CLR ...
  • 在這個互聯網時代,數據被稱為石油,由此數據安全是被看得尤為重要,本篇文章意在普及密碼學的基礎知識。 ...
  • 1 static DataTable ConvertJsonToTable(string jsonValue) 2 { 3 DataTable dt = (DataTable)JsonConvert.DeserializeObject(jsonValue, typeof(DataTable)); 4 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...