解读设计模式----简单工厂模式(SimpleFactory Pattern),你要什么我就给你什么
本文首發(fā)于博客園,地址:http://www.cnblogs.com/beniao/archive/2008/08/09/1263318.html?
?
一、模式概述
?????從設(shè)計(jì)模式的類(lèi)型上來(lái)說(shuō),簡(jiǎn)單工廠模式是屬于創(chuàng)建型模式,又叫做靜態(tài)工廠方法(Static Factory Method)模式,但不屬于23種GOF設(shè)計(jì)模式之一。簡(jiǎn)單工廠模式是由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類(lèi)的實(shí)例。簡(jiǎn)單工廠模式是工廠模式家族中最簡(jiǎn)單實(shí)用的模式,可以理解為是不同工廠模式的一個(gè)特殊實(shí)現(xiàn),學(xué)習(xí)了此模式可以為后面的很多中模式打下基礎(chǔ)。那好,我們就來(lái)了解下什么是簡(jiǎn)單工廠模式?
?
?????我們來(lái)分析一個(gè)現(xiàn)實(shí)生活中的案例,每天早晨起床洗唰后是干什么呢?吃早餐(這里只針對(duì)在外吃早餐的上班族)、坐車(chē)(我是窮人只有坐公交,當(dāng)然很多有錢(qián)人都自己有車(chē),這里不考慮這些)去公司上班、是這樣的嗎?OK,下面就來(lái)分析下吃早餐中的故事,大家先看看下面這個(gè)圖:
???????????????? ?????
?????當(dāng)我們?cè)谫I(mǎi)早餐的時(shí)候,早餐店里都賣(mài)得寫(xiě)什么呢?這點(diǎn)你有注意嗎?眾多食品擺在那里,你只對(duì)營(yíng)業(yè)員說(shuō)你要何種食品,他便會(huì)知道給你拿什么樣的食品給你,這說(shuō)明什么呢?如果用面向?qū)ο蟮乃枷雭?lái)理解的話(huà),營(yíng)業(yè)員在這里就充當(dāng)了一個(gè)工廠的角色,他負(fù)責(zé)根據(jù)你的請(qǐng)求返回你需要的食品對(duì)象。而這一點(diǎn)正是簡(jiǎn)單工廠模式的意圖。
?
二、模式意圖
?????簡(jiǎn)單工廠模式根據(jù)提供給他的數(shù)據(jù),返回幾個(gè)可能類(lèi)中的一個(gè)類(lèi)的實(shí)例。
?
三、模式UML圖?????
?????下面是簡(jiǎn)單工廠模式的示意性UML圖:
????????????????
?????如上圖,簡(jiǎn)單工廠模式UML我畫(huà)了兩種,詳細(xì)如下:
?????① 只有一個(gè)產(chǎn)品對(duì)象的簡(jiǎn)單工廠模式。?
?????② 帶有一個(gè)抽象產(chǎn)品對(duì)象的簡(jiǎn)單工廠模式。
?
四、模式參與者
??????工廠(Factory)角色:接受客戶(hù)端的請(qǐng)求,通過(guò)請(qǐng)求負(fù)責(zé)創(chuàng)建相應(yīng)的產(chǎn)品對(duì)象。
??????抽象產(chǎn)品(AbstractProduct)角色: 是工廠模式所創(chuàng)建對(duì)象的父類(lèi)或是共同擁有的接口??墒浅橄箢?lèi)或接口。
??????具體產(chǎn)品(ConcreteProduct)對(duì)象:工廠模式所創(chuàng)建的對(duì)象都是這個(gè)角色的實(shí)例。
?
五、模式實(shí)現(xiàn)
?????我們通過(guò)上面的分析,已經(jīng)清晰的知道了工廠模式中的各種角色和職責(zé),那工廠模式通過(guò)代碼是怎么實(shí)現(xiàn)的呢?OK,下面將繼續(xù)分析上面的吃早餐中的故事,做一個(gè)簡(jiǎn)單的示例實(shí)現(xiàn)。
?????1、首先我們來(lái)看看只有一個(gè)產(chǎn)品對(duì)象的簡(jiǎn)單工廠模式的實(shí)現(xiàn)。其實(shí)這很好理解,就當(dāng)?shù)昀镏毁u(mài)一種食品,這里以饅頭為例。
?1?///?<summary>?2?///?饅頭
?3?///?</summary>
?4?public?class?SteamedBread
?5?{
?6?????///?<summary>
?7?????///?構(gòu)造方法
?8?????///?</summary>
?9?????public?SteamedBread()
10?????{?}
11?
12?????///?<summary>
13?????///?銷(xiāo)售價(jià)格
14?????///?</summary>
15?????private?double?price=0.5;
16?????public?double?Price
17?????{
18?????????get?{?return?price;?}
19?????????set?{?price?=?value;?}
20?????}
21?}
?????
?????OK,產(chǎn)品對(duì)象建立好了,下面就是創(chuàng)建工廠(Factory)對(duì)象了。
?1?///?<summary>?2?///?工廠角色
?3?///?</summary>
?4?public?class?Factory
?5?{
?6?????///?<summary>
?7?????///?創(chuàng)建一個(gè)饅頭(SteamedBread)對(duì)象
?8?????///?</summary>
?9?????///?<returns></returns>
10?????public?static?SteamedBread?CreateInstance()
11?????{
12?????????return?new?SteamedBread();
13?????}
14?}
?
?????此時(shí),客戶(hù)端可以這樣來(lái)調(diào)用:
1?public?class?Client2?{
3?????public?static?void?Main(string[]?args)
4?????{
5?????????//通過(guò)工廠創(chuàng)建一個(gè)產(chǎn)品的實(shí)例
6?????????SteamedBread?sb?=?Factory.CreateInstance();
7?????????Console.WriteLine("饅頭{0}元一個(gè)!",?sb.Price);
8?????}
9?}
?
?????如上就完成了一個(gè)簡(jiǎn)單工廠模式的簡(jiǎn)單實(shí)現(xiàn),一個(gè)產(chǎn)品和一個(gè)工廠,工廠負(fù)責(zé)創(chuàng)建這個(gè)產(chǎn)品。但是者種實(shí)現(xiàn)有一定的缺陷,為每一種產(chǎn)品創(chuàng)建一個(gè)靜態(tài)方法來(lái)完成產(chǎn)品對(duì)象的創(chuàng)建,如果有多個(gè)產(chǎn)品則需要定義多個(gè)靜態(tài)方法分別返回不同的對(duì)象,用設(shè)計(jì)原則來(lái)說(shuō)的話(huà)這樣的實(shí)現(xiàn)不符合依賴(lài)倒置原則(DIP)。如果系統(tǒng)里只有一個(gè)單獨(dú)的產(chǎn)品對(duì)象,那么采用這種實(shí)現(xiàn)是完全可以的。UML圖如下:
????????????????????????????
?
?????2、帶抽象產(chǎn)品(AbstractProduct)角色的簡(jiǎn)單工廠模式實(shí)現(xiàn)
?????從上面分析中得知,這種實(shí)現(xiàn)得為每一種產(chǎn)品創(chuàng)建一個(gè)靜態(tài)方法來(lái)完成產(chǎn)品對(duì)象的創(chuàng)建。雖然帶有簡(jiǎn)單工廠的性質(zhì),但是又好象不能夠完全體現(xiàn)出簡(jiǎn)單工廠模式的意圖。簡(jiǎn)單工廠的意圖是:根據(jù)提供給他的數(shù)據(jù),返回幾個(gè)可能類(lèi)中的一個(gè)類(lèi)的實(shí)例。根據(jù)意圖出發(fā)進(jìn)行分析,要實(shí)現(xiàn)完全滿(mǎn)足簡(jiǎn)單工廠模式意圖的程序,也就得根據(jù)提供給工廠的數(shù)據(jù),讓工廠根據(jù)這個(gè)數(shù)據(jù)來(lái)進(jìn)行判斷,然后返回相應(yīng)的對(duì)象。OK,看看是下面這樣的嗎?
??????????????????????????
?????示意性代碼如下:
?1?///?<summary>?2?///?食品接口----扮演抽象產(chǎn)品角色
?3?///?</summary>
?4?public?interface?IFood
?5?{
?6?????///?<summary>
?7?????///?每種食品都有銷(xiāo)售價(jià)格,這里應(yīng)該作為共性提升到父類(lèi)或是接口來(lái)
?8?????///?由于我們只需要得到價(jià)格,所以這里就只提供get屬性訪問(wèn)器
?9?????///?</summary>
10?????double?price{get;}
11?}
12?------------------------------------------------------------------------------------
13?///?<summary>
14?///?饅頭
15?///?</summary>
16?public?class?SteamedBread:IFood
17?{
18?????///?<summary>
19?????///?構(gòu)造方法
20?????///?</summary>
21?????public?SteamedBread()
22?????{?}
23?
24?????public?double?price
25?????{
26?????????get
27?????????{
28?????????????return??0.5;
29?????????}
30?????}
31?}
32?------------------------------------------------------------------------------------
33?///?<summary>
34?///?包子
35?///?</summary>
36?public?class?SteamedStuffed:IFood
37?{
38?????public?SteamedStuffed()
39?????{?}
40?
41?????///?<summary>
42?????///?銷(xiāo)售價(jià)格
43?????///?</summary>
44?????public?double?price
45?????{
46?????????get
47?????????{
48?????????????return??0.6;??//0.6元一個(gè)
49?????????}
50?????}
51?}
52?------------------------------------------------------------------------------------
53?///?<summary>
54?///?工廠角色
55?///?</summary>
56?public?class?Factory
57?{
58?????///?<summary>
59?????///?創(chuàng)建一個(gè)饅頭(SteamedBread)對(duì)象
60?????///?</summary>
61?????///?<returns></returns>
62?????public?static?IFood?CreateInstance(string?key)
63?????{
64?????????if?(key?==?"饅頭")
65?????????{
66?????????????return?new?SteamedBread();
67?????????}
68?????????else
69?????????{
70?????????????return?new?SteamedStuffed();
71?????????}
72?????}
73?}
74?------------------------------------------------------------------------------------
75?public?class?Client
76?{
77?????public?static?void?Main(string[]?args)
78?????{
79?????????//通過(guò)工廠創(chuàng)建一個(gè)產(chǎn)品的實(shí)例
80?????????IFood?food?=?Factory.CreateInstance("饅頭");
81?????????Console.WriteLine("饅頭{0}元一個(gè)!",?food.price);
82?
83?????????food?=?Factory.CreateInstance("包子");
84?????????Console.WriteLine("包子{0}元一個(gè)!",?food.price);
85?????}
86?}
?
?????此時(shí)的設(shè)計(jì)就已經(jīng)完全符合簡(jiǎn)單工廠模式的意圖了。顧客(Client)對(duì)早餐店?duì)I業(yè)員(Factory)說(shuō),我要“饅頭”,于是營(yíng)業(yè)員便根據(jù)顧客所提供的數(shù)據(jù)(饅頭),去眾多食品中找,找到了然后就拿給顧客。
?
?????3、模式的演變實(shí)現(xiàn)
?????有些情況下Simple Factory可以由抽象產(chǎn)品角色扮演,一個(gè)抽象產(chǎn)品類(lèi)同時(shí)是子類(lèi)的工廠。也就是說(shuō),抽象產(chǎn)品角色扮演兩種角色和職責(zé),出了基本的定義還還兼任工廠角色的職責(zé),負(fù)責(zé)產(chǎn)品的創(chuàng)建工作。這里我們?cè)谏厦娴睦踊A(chǔ)上適當(dāng)修改一下OK了,新建立一個(gè)抽象類(lèi)(Evolution):
?1?///?<summary>?2?///?兼任抽象產(chǎn)品角色和工廠角色兩種角色
?3?///?</summary>
?4?public?abstract?class?Evolution
?5?{
?6?????///?<summary>
?7?????///?共性字段
?8?????///?</summary>
?9?????private?double?price;
10?????public?double?Price
11?????{
12?????????get?{?return?price;?}
13?????????set?{?price?=?value;?}
14?????}
15?
16?
17?????public?static?Evolution?CreateInstance(string?key)
18?????{
19?????????if?(key?==?"饅頭")
20?????????{
21?????????????return?new?SteamedBread();
22?????????}
23?????????else
24?????????{
25?????????????return?new?SteamedStuffed();
26?????????}
27?????}
28?}
?
?????那現(xiàn)在,具體的產(chǎn)品對(duì)象的設(shè)計(jì)也應(yīng)該修改了,把原來(lái)實(shí)現(xiàn)于IFood接口改為繼承此抽象類(lèi),如下:
?1?public?class?SteamedBread?:?Evolution?2?{
?3?????public?SteamedBread()
?4?????{
?5?????????this.Price?=?0.5;? //在構(gòu)造方法里初始話(huà)屬性的值
?6?????}
?7?}
?8?
?9?public?class?SteamedStuffed?:?Evolution
10?{
11?????public?SteamedStuffed()
12?????{
13?????????this.Price?=?0.6;
14?????}
15?}
?????
?????通過(guò)上面的演化,此時(shí)客戶(hù)端的調(diào)用如下:
1?public?class?Client2?{
3?????public?static?void?Main(string[]?args)
4?????{
5?????????Evolution?el?=?Evolution.CreateInstance("包子");
6?????????Console.WriteLine("包子{0}元一個(gè)!",?el.Price);
7?????}
8?}
?
?????UML草圖如下:
????????????????????????????????? ?????
?????在實(shí)際的開(kāi)發(fā)中,這種演化是很適用的,可以說(shuō)是一種編程技巧吧。
?
?????4、模式的其他演變
?????如果系統(tǒng)中只有唯一的一個(gè)具體產(chǎn)品對(duì)象,那么可以省略抽象產(chǎn)品角色。這一種其實(shí)也就是本錢(qián)前面的第一種模式實(shí)現(xiàn)。
?????如果抽象產(chǎn)品角色省略,那么工廠角色就可以與具體產(chǎn)品角色合并。也就是說(shuō)一個(gè)產(chǎn)品類(lèi)就是自身的工廠。這樣把原有三個(gè)獨(dú)立的角色:抽象產(chǎn)品角色、具體產(chǎn)品角色和工廠角色合并為一個(gè),這個(gè)類(lèi)自己負(fù)責(zé)創(chuàng)建自己的實(shí)例。
?
?????注:以上演變可以從上面的程序代碼中直接修改而來(lái),這里我就不貼代碼了。???
?
六、模式優(yōu)缺點(diǎn)
??????工廠類(lèi)含有必要的判斷邏輯,可以決定在什么時(shí)候創(chuàng)建哪一個(gè)產(chǎn)品類(lèi)的實(shí)例,客戶(hù)端可以免除直接創(chuàng)建產(chǎn)品對(duì)象的責(zé)任,而僅僅"消費(fèi)"產(chǎn)品。簡(jiǎn)單工廠模式通過(guò)這種做法實(shí)現(xiàn)了對(duì)責(zé)任的分割。
??????當(dāng)產(chǎn)品有復(fù)雜的多層等級(jí)結(jié)構(gòu)時(shí),工廠類(lèi)只有自己,以不變應(yīng)萬(wàn)變,就是模式的缺點(diǎn)。因?yàn)楣S類(lèi)集中了所有產(chǎn)品創(chuàng)建邏輯,一旦不能正常工作,整個(gè)系統(tǒng)都要受到影響。
??????系統(tǒng)擴(kuò)展困難,一旦添加新產(chǎn)品就不得不修改工廠邏輯,有可能造成工廠邏輯過(guò)于復(fù)雜,違背了"開(kāi)放--封閉"原則(OCP).另外,簡(jiǎn)單工廠模式通常使用靜態(tài)工廠方法,這使得無(wú)法由子類(lèi)繼承,造成工廠角色無(wú)法形成基于繼承的等級(jí)結(jié)構(gòu)。
?
七、相關(guān)模式
??????工廠方法模式:每個(gè)產(chǎn)品由一個(gè)專(zhuān)門(mén)的工廠來(lái)負(fù)責(zé)創(chuàng)建。是一種只有唯一一個(gè)產(chǎn)品的實(shí)現(xiàn),帶有簡(jiǎn)單工廠的性質(zhì)。
??????抽象工廠模式:大致和工廠方法相同。
??????單例模式:單例的實(shí)現(xiàn)和上面模式演變中的最后一種很相似,只要把構(gòu)造器私有便OK。
?
八、參考資料
?????Addison-Wesley,1995,p.185. 中文版:《設(shè)計(jì)模式:可復(fù)用的面向?qū)ο筌浖幕A(chǔ)》 李英軍等譯.
?????Alan Sharroway & James r.Trott.中文版:《設(shè)計(jì)模式精解
?????張逸? 著《軟件設(shè)計(jì)精要與模式》
總結(jié)
以上是生活随笔為你收集整理的解读设计模式----简单工厂模式(SimpleFactory Pattern),你要什么我就给你什么的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java线程基础知识
- 下一篇: 迈出从3K到1W的重要一步——掌握设计模