建造者模式(Builder Pattern)(转自TerryLee)
概述?
在軟件系統(tǒng)中,有時(shí)候面臨著“一個(gè)復(fù)雜對(duì)象”的創(chuàng)建工作,其通常由各個(gè)部分的子對(duì)象用一定的算法構(gòu)成;由于需求的變化,這個(gè)復(fù)雜對(duì)象的各個(gè)部分經(jīng)常面臨著劇烈的變化,但是將它們組合在一起的算法確相對(duì)穩(wěn)定。如何應(yīng)對(duì)這種變化?如何提供一種“封裝機(jī)制”來(lái)隔離出“復(fù)雜對(duì)象的各個(gè)部分”的變化,從而保持系統(tǒng)中的“穩(wěn)定構(gòu)建算法”不隨著需求改變而改變?這就是要說(shuō)的建造者模式。
本文通過(guò)現(xiàn)實(shí)生活中的買KFC的例子,用圖解的方式來(lái)詮釋建造者模式。
意圖?
將一個(gè)復(fù)雜的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。
模型圖?
?
生活中的例子?
生成器模式將復(fù)雜對(duì)象的構(gòu)建與對(duì)象的表現(xiàn)分離開(kāi)來(lái),這樣使得同樣的構(gòu)建過(guò)程可以創(chuàng)建出不同的表現(xiàn)。這種模式用于快餐店制作兒童餐。典型的兒童餐包括一個(gè)主食,一個(gè)輔食,一杯飲料和一個(gè)玩具(例如漢堡、炸雞、可樂(lè)和玩具車)。這些在不同的兒童餐中可以是不同的,但是組合成兒童餐的過(guò)程是相同的。無(wú)論顧客點(diǎn)的是漢堡,三名治還是雞肉,過(guò)程都是一樣的。柜臺(tái)的員工直接把主食,輔食和玩具放在一起。這些是放在一個(gè)袋子中的。飲料被倒入杯中,放在袋子外邊。這些過(guò)程在相互競(jìng)爭(zhēng)的餐館中是同樣的。
?
實(shí)現(xiàn)過(guò)程圖解?
在這里我們還是以去KFC店買套餐為例子,示意圖如下:
?
客戶端:顧客。想去買一套套餐(這里面包括漢堡,可樂(lè),薯?xiàng)l),可以有1號(hào)和2號(hào)兩種套餐供顧客選擇。
指導(dǎo)者角色:收銀員。知道顧客想要買什么樣的套餐,并告訴餐館員工去準(zhǔn)備套餐。
建造者角色:餐館員工。按照收銀員的要求去準(zhǔn)備具體的套餐,分別放入漢堡,可樂(lè),薯?xiàng)l等。
產(chǎn)品角色:最后的套餐,所有的東西放在同一個(gè)盤子里面。
下面開(kāi)始我們的買套餐過(guò)程。
1.客戶創(chuàng)建Derector對(duì)象,并用它所想要的Builder對(duì)象進(jìn)行配置。顧客進(jìn)入KFC店要買套餐,先找到一個(gè)收銀員,相當(dāng)于創(chuàng)建了一個(gè)指導(dǎo)者對(duì)象。這位收銀員給出兩種套餐供顧客選擇:1普通套餐,2黃金套餐。完成的工作如時(shí)序圖中紅色部分所示。
產(chǎn)品(套餐)類:
?
代碼 1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Collections;
6
7 namespace BuilderDemo
8 {
9 /// <summary>
10 /// Food類,既產(chǎn)品類
11 /// </summary>
12 public class Food
13 {
14 Hashtable food = new Hashtable();
15
16 /// <summary>
17 /// 添加食品
18 /// </summary>
19 /// <param name="strName">食品名稱</param>
20 /// <param name="Price">價(jià)格</param>
21 public void Add(string strName,string Price)
22 {
23 food.Add(strName,Price);
24 }
25
26 /// <summary>
27 /// 顯示食品清單
28 /// </summary>
29 public void Show()
30 {
31 IDictionaryEnumerator myEnumerator = food.GetEnumerator();
32 Console.WriteLine("Food List:");
33 Console.WriteLine("------------------------------");
34 string strfoodlist = "";
35 while(myEnumerator.MoveNext())
36 {
37 strfoodlist = strfoodlist + "\n\n" + myEnumerator.Key.ToString();
38 strfoodlist = strfoodlist + ":\t" +myEnumerator.Value.ToString();
39 }
40 Console.WriteLine(strfoodlist);
41 Console.WriteLine("\n------------------------------");
42 }
43 }
44
45 }
46
2.指導(dǎo)者通知建造器。收銀員(指導(dǎo)者)告知餐館員工準(zhǔn)備套餐。這里我們準(zhǔn)備套餐的順序是:放入漢堡,可樂(lè)倒入杯中,薯?xiàng)l放入盒中,并把這些東西都放在盤子上。這個(gè)過(guò)程對(duì)于普通套餐和黃金套餐來(lái)說(shuō)都是一樣的,不同的是它們的漢堡,可樂(lè),薯?xiàng)l價(jià)格不同而已。如時(shí)序圖紅色部分所示:
?
代碼 1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace BuilderDemo
7 {
8 /// <summary>
9 /// FoodManager類,即指導(dǎo)者
10 /// </summary>
11 class FoodManager
12 {
13 public void Construct(Builder builder)
14 {
15 builder.BuildHamb();
16
17 builder.BuildCoke();
18
19 builder.BuildChip();
20 }
21 }
22 }
23
?
?
3.建造者處理指導(dǎo)者的要求,并將部件添加到產(chǎn)品中。餐館員工(建造者)按照收銀員要求的把對(duì)應(yīng)的漢堡,可樂(lè),薯?xiàng)l放入盤子中。這部分是建造者模式里面富于變化的部分,因?yàn)轭櫩瓦x擇的套餐不同,套餐的組裝過(guò)程也不同,這步完成產(chǎn)品對(duì)象的創(chuàng)建工作。
程序?qū)崿F(xiàn):
?
?
代碼 1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace BuilderDemo
7 {
8 /// <summary>
9 /// Builder類,即抽象建造者類,構(gòu)造套餐
10 /// </summary>
11 public abstract class Builder
12 {
13 /// <summary>
14 /// 添加漢堡
15 /// </summary>
16 public abstract void BuildHamb();
17
18 /// <summary>
19 /// 添加可樂(lè)
20 /// </summary>
21 public abstract void BuildCoke();
22
23 /// <summary>
24 /// 添加薯?xiàng)l
25 /// </summary>
26 public abstract void BuildChip();
27
28 /// <summary>
29 /// 返回結(jié)果
30 /// </summary>
31 /// <returns>食品對(duì)象</returns>
32 public abstract Food GetFood();
33 }
34
35 }
36
?
代碼 1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace BuilderDemo
7 {
8 /// <summary>
9 /// NormalBuilder類,具體構(gòu)造者,普通套餐
10 /// </summary>
11 class NormalBuilder:Builder
12 {
13 private Food NormalFood = new Food();
14
15 public override void BuildHamb()
16 {
17 NormalFood.Add("NormalHamb","¥10.50");
18 }
19
20 public override void BuildCoke()
21 {
22 NormalFood.Add("CokeCole","¥4.50");
23 }
24
25 public override void BuildChip()
26 {
27 NormalFood.Add("FireChips","¥2.00");
28 }
29
30 public override Food GetFood()
31 {
32 return NormalFood;
33 }
34
35 }
36 }
37
?
代碼 1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace BuilderDemo
7 {
8 /// <summary>
9 /// GoldBuilder類,具體構(gòu)造者,黃金套餐
10 /// </summary>
11 class GoldBuilder:Builder
12 {
13 private Food GoldFood = new Food();
14
15 public override void BuildHamb()
16 {
17 GoldFood.Add("GoldHamb","¥13.50");
18 }
19
20 public override void BuildCoke()
21 {
22 GoldFood.Add("CokeCole","¥4.50");
23 }
24
25 public override void BuildChip()
26 {
27 GoldFood.Add("FireChips","¥3.50");
28 }
29
30 public override Food GetFood()
31 {
32 return GoldFood;
33 }
34
35 }
36 }
37
?
4.客戶從建造者檢索產(chǎn)品。從餐館員工準(zhǔn)備好套餐后,顧客再?gòu)牟宛^員工那兒拿回套餐。這步客戶程序要做的僅僅是取回已經(jīng)生成的產(chǎn)品對(duì)象,如時(shí)序圖中紅色部分所示。
完整的客戶程序:
?
代碼 1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Reflection;
6 using System.Configuration;
7
8 namespace BuilderDemo
9 {
10 /// <summary>
11 /// 客戶端
12 /// </summary>
13 class Program
14 {
15 static void Main(string[] args)
16 {
17 FoodManager foodmanager = new FoodManager();
18
19 Builder instance;
20
21 Console.WriteLine("Please Enter Food No(1-2):");
22
23 string No = Console.ReadLine();
24
25 string foodType = ConfigurationSettings.AppSettings["No"+No];
26
27 //instance= Activator.CreateInstance(Type.GetType(foodType)) as Builder;
28
29 //instance = new NormalBuilder();
30
31 instance = (Builder)Assembly.Load("BuilderDemo").CreateInstance("BuilderDemo." + foodType);
32
33 foodmanager.Construct(instance);
34
35 Food food = instance.GetFood();
36 food.Show();
37
38 Console.ReadLine();
39 }
40 }
41 }
42
通過(guò)分析不難看出,在這個(gè)例子中,在準(zhǔn)備套餐的過(guò)程是穩(wěn)定的,即按照一定的步驟去做,而套餐的組成部分則是變化的,有可能是普通套餐或黃金套餐等。這個(gè)變化就是建造者模式中的“變化點(diǎn)“,就是我們要封裝的部分。
?
實(shí)現(xiàn)要點(diǎn)?
1、建造者模式主要用于“分步驟構(gòu)建一個(gè)復(fù)雜的對(duì)象”,在這其中“分步驟”是一個(gè)穩(wěn)定的算法,而復(fù)雜對(duì)象的各個(gè)部分則經(jīng)常變化。
2、產(chǎn)品不需要抽象類,特別是由于創(chuàng)建對(duì)象的算法復(fù)雜而導(dǎo)致使用此模式的情況下或者此模式應(yīng)用于產(chǎn)品的生成過(guò)程,其最終結(jié)果可能差異很大,不大可能提煉出一個(gè)抽象產(chǎn)品類。
3、創(chuàng)建者中的創(chuàng)建子部件的接口方法不是抽象方法而是空方法,不進(jìn)行任何操作,具體的創(chuàng)建者只需要覆蓋需要的方法就可以,但是這也不是絕對(duì)的,特別是類似文本轉(zhuǎn)換這種情況下,缺省的方法將輸入原封不動(dòng)的輸出是合理的缺省操作。
4、前面我們說(shuō)過(guò)的抽象工廠模式(Abtract Factory)解決“系列對(duì)象”的需求變化,Builder模式解決“對(duì)象部分”的需求變化,建造者模式常和組合模式(Composite Pattern)結(jié)合使用。
效果?
1、建造者模式的使用使得產(chǎn)品的內(nèi)部表象可以獨(dú)立的變化。使用建造者模式可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)。
2、每一個(gè)Builder都相對(duì)獨(dú)立,而與其它的Builder無(wú)關(guān)。
3、可使對(duì)構(gòu)造過(guò)程更加精細(xì)控制。
4、將構(gòu)建代碼和表示代碼分開(kāi)。
5、建造者模式的缺點(diǎn)在于難于應(yīng)付“分步驟構(gòu)建算法”的需求變動(dòng)。
適用性?
以下情況應(yīng)當(dāng)使用建造者模式:
1、需要生成的產(chǎn)品對(duì)象有復(fù)雜的內(nèi)部結(jié)構(gòu)。
2、需要生成的產(chǎn)品對(duì)象的屬性相互依賴,建造者模式可以強(qiáng)迫生成順序。
3、?在對(duì)象創(chuàng)建過(guò)程中會(huì)使用到系統(tǒng)中的一些其它對(duì)象,這些對(duì)象在產(chǎn)品對(duì)象的創(chuàng)建過(guò)程中不易得到。
應(yīng)用場(chǎng)景?
1、???RTF文檔交換格式閱讀器。
2、???.NET環(huán)境下的字符串處理StringBuilder,這是一種簡(jiǎn)化了的建造者模式。
3、???……
總結(jié)
建造者模式的實(shí)質(zhì)是解耦組裝過(guò)程和創(chuàng)建具體部件,使得我們不用去關(guān)心每個(gè)部件是如何組裝的。
?
作者:TerryLee
出處:http://terrylee.cnblogs.com?
建造者模式(Builder Pattern)
轉(zhuǎn)載于:https://www.cnblogs.com/tianyutingxy/archive/2010/10/20/1856373.html
總結(jié)
以上是生活随笔為你收集整理的建造者模式(Builder Pattern)(转自TerryLee)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 错误提示“未能加载文件或程序集“Micr
- 下一篇: OleDb执行Oracle带自定义函数的