文章目錄
一、 Factory 方法(Factory Method)模式
Factory 方法(FactoryMethod)模式是類的建立模式,其用意是定義一個建立產品對象的工廠介面,將實際建立工作延遲到子類中。
Factory 方法模式是簡單原廠模式的進一步抽象和推廣。由於使用了多態性,Factory 方法模式保持了簡單原廠模式的優點,而且克服了它的缺點。
在Factory 方法模式中,核心的工廠類不再負責所有產品的建立,而是將具體建立工作交給子類去做。這個核心類僅僅負責給出具體工廠必須實現的介面,而不接觸哪一個產品類被執行個體化這種細節。這使得Factory 方法模式可以允許系統在不修改工廠角色的情況下引進新產品。
在Factory Method模式中,工廠類與產品類往往具有平行的等級結構,它們之間一一對應。
二、 Factory Method模式角色與結構:
抽象工廠(Creator)角色:是Factory 方法模式的核心,與應用程式無關。任何在模式中建立的對象的工廠類必須實現這個介面。
具體工廠(Concrete Creator)角色:這是實現抽象工廠介面的具體工廠類,包含與應用程式密切相關的邏輯,並且受到應用程式調用以建立產品對象。在中有兩個這樣的角色:BulbCreator與TubeCreator。
抽象產品(Product)角色:Factory 方法模式所建立的對象的超類型,也就是產品對象的共同父類或共同擁有的介面。在中,這個角色是Light。
具體產品(Concrete Product)角色:這個角色實現了抽象產品角色所定義的介面。某具體產品有專門的具體工廠建立,它們之間往往一一對應。
三、 程式舉例:using System;
public abstract class Light
{
public abstract void TurnOn();
public abstract void TurnOff();
}
public class BulbLight : Light
{
public override void TurnOn()
{ Console.WriteLine("Bulb Light is Turned on"); }
public override void TurnOff()
{ Console.WriteLine("Bulb Light is Turned off"); }
}
public class TubeLight : Light
{
public override void TurnOn()
{ Console.WriteLine("Tube Light is Turned on"); }
public override void TurnOff()
{ Console.WriteLine("Tube Light is Turned off"); }
}
public abstract class Creator
{
public abstract Light factory();
}
public class BulbCreator : Creator
{
public override Light factory()
{ return new BulbLight(); }
}
public class TubeCreator : Creator
{
public override Light factory()
{ return new TubeLight(); }
}
public class Client
{
public static void Main()
{
Creator c1 = new BulbCreator();
Creator c2 = new TubeCreator();
Light l1 = c1.factory();
Light l2 = c2.factory();
l1.TurnOn();
l1.TurnOff();
Console.WriteLine("-----------------");
l2.TurnOn();
l2.TurnOff();
}
}
Factory 方法的活動順序圖表
活動過程包括:
用戶端建立BulbCreator對象,用戶端持有此對象的類型是Creator,而實際類型是BulbCreator。然後用戶端調用BulbCreator的factory方法,之後BulbCreator調用BulbLight的建構函式創造出產品BulbLight對象。
四、 Factory 方法模式與簡單原廠模式
Factory 方法模式與簡單原廠模式再結構上的不同不是很明顯。Factory 方法類的核心是一個抽象工廠類,而簡單原廠模式把核心放在一個具體類上。
Factory 方法模式之所以有一個別名叫多態性原廠模式是因為具體工廠類都有共同的介面,或者有共同的抽象父類。
當系統擴充需要添加新的產品對象時,僅僅需要添加一個具體對象以及一個具體工廠對象,原有工廠對象不需要進行任何修改,也不需要修改用戶端,很好的符合了"開放-封閉"原則。而簡單原廠模式在添加新產品對象後不得不修改Factory 方法,擴充性不好。
Factory 方法模式退化後可以演變成簡單原廠模式。
五、 Factory Method模式演化
使用介面或抽象類別
抽象工廠角色和抽象場頻角色都可以選擇由介面或抽象類別實現。
使用多個Factory 方法
抽象工廠角色可以規定出多於一個的Factory 方法,從而使具體工廠角色實現這些不同的Factory 方法,這些方法可以提供不同的商業邏輯,以滿足提供不同的產品對象的任務。
產品的迴圈使用
Factory 方法總是調用產品類的建構函式以建立一個新的產品執行個體,然後將這個執行個體提供給用戶端。而在實際情形中,Factory 方法所做的事情可以相當複雜。
一個常見的複雜邏輯就是迴圈使用產品對象。工廠對象將已經建立過的產品登記到一個聚集中,然後根據客戶所請求的產品狀態,向聚集查詢。如果有滿足要求的產品對象,就直接將產品返回用戶端;如果聚集中沒有這樣的產品對象,那麼就建立一個新的滿足要求的產品對象,然後將這個對象登記到聚集中,再返還給用戶端。"享元模式(Flyweight Pattern)"就是這樣一個模式。
多態性的喪失和模式的退化
一個Factory 方法模式的實現依賴於工廠角色和產品角色的多態性。在有些情況下,這個模式可以出現退化。
Factory 方法返回的類型應當是抽象類別型,而不是具體類型。調用Factory 方法的用戶端應當依賴抽象產品編程,而不是具體產品。如果工廠僅僅返回一個具體產品對象,便違背了Factory 方法的用意,發生退化,這時就不再是原廠模式了。
工廠的等級結構:工廠對象應當有一個抽象的超類型。如果等級結構中只有一個具體工廠類的話,抽象工廠就可以省略,發生了退化。
六、 Factory Method模式與其它模式的關係
與Factory 方法模式有關的模式還包括:
模板方法模式、MVC模式、享元模式、備忘錄模式
七、 另外一個例子// Factory Method pattern -- Real World example
using System;
using System.Collections;
// "Product"
abstract class Page
{
}
// "ConcreteProduct"
class SkillsPage : Page
{
}
// "ConcreteProduct"
class EducationPage : Page
{
}
// "ConcreteProduct"
class ExperiencePage : Page
{
}
// "ConcreteProduct"
class IntroductionPage : Page
{
}
// "ConcreteProduct"
class ResultsPage : Page
{
}
// "ConcreteProduct"
class ConclusionPage : Page
{
}
// "ConcreteProduct"
class SummaryPage : Page
{
}
// "ConcreteProduct"
class BibliographyPage : Page
{
}
// "Creator"
abstract class Document
{
// Fields
protected ArrayList pages = new ArrayList();
// Constructor
public Document()
{
this.CreatePages();
}
// Properties
public ArrayList Pages
{
get{ return pages; }
}
// Factory Method
abstract public void CreatePages();
}
// "ConcreteCreator"
class Resume : Document
{
// Factory Method implementation
override public void CreatePages()
{
pages.Add( new SkillsPage() );
pages.Add( new EducationPage() );
pages.Add( new ExperiencePage() );
}
}
// "ConcreteCreator"
class Report : Document
{
// Factory Method implementation
override public void CreatePages()
{
pages.Add( new IntroductionPage() );
pages.Add( new ResultsPage() );
pages.Add( new ConclusionPage() );
pages.Add( new SummaryPage() );
pages.Add( new BibliographyPage() );
}
}
/**//// <summary>
/// FactoryMethodApp test
/// </summary>
class FactoryMethodApp
{
public static void Main( string[] args )
{
Document[] docs = new Document[ 2 ];
// Note: constructors call Factory Method
docs[0] = new Resume();
docs[1] = new Report();
// Display document pages
foreach( Document document in docs )
{
Console.WriteLine( " " + document + " ------- " );
foreach( Page page in document.Pages )
Console.WriteLine( " " + page );
}
}
}
參考文獻:
閻宏,《Java與模式》,電子工業出版社
[美]James W. Cooper,《C#設計模式》,電子工業出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中國電力出版社
[美]Robert C. Martin,《敏捷式軟體開發 (Agile Software Development)-原則、模式與實踐》,清華大學出版社
[美]Don Box, Chris Sells,《.NET本質論 第1卷:公用語言運行庫》,中國電力出版社
posted on 2004-08-26 00:23 呂震宇 閱讀(10865) 評論(27) 編輯 收藏 引用 網摘 所屬分類: 設計模式
評論# re: C#設計模式(5)-Factory Method Pattern 2004-08-26 02:37 寒楓天傷 呵,你也睡得挺晚的。
最近那麼有精神,是不是放假了? 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2004-08-26 08:25 呂震宇 這個星期老婆去桂林了。 : - ) 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2004-09-07 11:29 John.J.Dengba 非常好的文章!使我對Factory 方法有了新的認識,特別是最後的例子。感謝樓主!
BTW:哈哈!我老婆帶著我女兒去嶽母家小住時,我也睡得很晚,看來大家都是這樣吧。:P 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-03-11 11:17 calfenyin 我覺得最後一個例子應該是Builder 模式 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-03-14 09:43 Rolf 去看一下本系列的Builder模式的第4條,簡單解釋了Builder和Factory的異同。實際上2者是建立過程中著眼點不同,一個是建立這個動作的抽象,另一個是建立後初始化這個過程的抽象。 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-03-15 14:18 calfenyin 可不可以這樣理解:
builder模式下 在 director.Construct之前 product已經產生了
director.Construct只是都product進行初始化
而factory模式下 product 是由factory產生出來的 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-04-14 23:49 idior 指導一下
http://www.pspsoft.com/idior/archive/2005/04/14/137913.html 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-04-21 13:39 seven 初學設計模式,還請呂老師解惑!
在您的文章中提到“使用多個Factory 方法:抽象工廠角色可以規定出多於一個的Factory 方法,從而使具體工廠角色實現這些不同的Factory 方法,這些方法可以提供不同的商業邏輯,以滿足提供不同的產品對象的任務。”我對“商業邏輯”不知道理解的對不對:抽象工廠角色中的每一個Factory 方法都是返回一種產品的抽象對象,正是這種抽象對象代表了一種商業邏輯。
我對商業邏輯的概念理解模糊,覺得您的最後一個例子體現了商業邏輯:class Resume : Document
{
// Factory Method implementation
override public void CreatePages()
{
pages.Add( new SkillsPage() );
pages.Add( new EducationPage() );
pages.Add( new ExperiencePage() );
}
}
我的理解是通過多種的產品組合,體現一些特定業務,不知道這樣理解對不對?
這應該是兩種不同的體現商務邏輯的方式吧?
回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-06-20 11:27 Terry 呂震宇,你好,我剛剛接觸Pattern不久,有個問題向您請教:
在簡單工廠中,使用參數決定建立哪個具體產品類的執行個體,返回抽象產品類的介面;當增加一個具體產品類時,不需要更改客戶代碼。(因為選擇語句在工廠類提供的方法中實現)
而在Factory 方法中,使用具體工廠類建立具體產品類,這樣一來,客戶代碼需要事先判斷使用哪個具體工廠來建立執行個體,因此當增加具體產品類時,客戶代碼需要改變!!!(因為選擇語句在客戶代碼中)
那麼,Factory 方法究竟好在何處呢?
landx_terry@hotmail.com
謝謝!
回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-06-20 19:08 呂震宇 Terry:
你好,你說中了問題的關鍵。其實上面原廠模式的代碼過於簡單,以至於產生上面的誤解。其實“依賴注入(或控制反轉)Ioc”模式以及我在《設計模式隨筆-讓眾口不再難調 http://www.cnblogs.com/zhenyulu/articles/81761.html》中提到的“條件外置”解決的就是你說的問題。
在一個比較大的系統中,往往是多組並行開發。所以軟體設計可以分步並行開發。上面代碼開發過程中可以如此安排。1)由系統架構師設計好抽象產品和抽象工廠。2.1)多組並行開發具體產品和具體工廠。2.2)與此同時另外一組使用依賴注入技術開發主程式。在1的工作完成後2.1與2.2是可以並行的。按上面方案很可能產生3個Assembly。最後通過設定檔完成組裝。
因此在實際應用時,主程式的那段代碼是利用設定檔“注入”得到的,或者主程式是單獨開發,因此可以確保不知道具體工廠是誰。Wayfarer的一篇文章曾循序漸進的討論過系統如何演化,如何引入設定檔等,只是記不起名字了,你可以到他的Blog上看看。 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-07-06 09:18 xzq686 寫的非常好,多謝呂老師. 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-07-15 15:03 oneway 謝謝,寫得好。
謝謝老師。
繼續關注
回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2005-12-23 11:13 gshope 在Factory Method模式中,工廠類與產品類往往具有平行的等級結構,它們之間一一對應。
................................................................
糾正一下,並非一定要"一一對應"和"平行等級結構",例如在開始的例子中,如果TubeLight 是BulbLight 的子類,也是可以的 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2006-01-16 17:04 qiucx0161 上面代碼開發過程中可以如此安排。1)由系統架構師設計好抽象產品和抽象工廠。2.1)多組並行開發具體產品和具體工廠。2.2)與此同時另外一組使用依賴注入技術開發主程式。在1的工作完成後2.1與2.2是可以並行的。按上面方案很可能產生3個Assembly。最後通過設定檔完成組裝。
非常正確。 事實上,這個設計模式用在組件開發中是非常有用的,而且可以通過reflect並把具體的類名已經產生執行個體的參數傳入工廠來產生執行個體。 java和csharp都是通用的,在這個點上。 回複 更多評論
# 你好,想請教一下 2006-01-20 13:25 冰&峰 你好,我想請教一下你的代碼是怎麼粘上去的,看起來很舒服 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2006-03-08 21:51 ^^ 想問一個問題,如果我把產品的建構函式申明為internal的話。這樣客戶代碼就不能將產品介面和產品實現直接耦合。只能通過工廠來建立,這樣是不是符合原廠模式的精神呢?請賜教。 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2006-05-01 11:28 ipiggg 看到最後的例子,我想到了便當。
便當由菜組成,某些菜構成一份
回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2006-06-13 23:30 LEEM 不是很清楚這些模式是怎麼命名的,個人認為“多態性原廠模式”比“Factory 方法模式”更能反映模式的實際情況。“Factory 方法模式”這個方法不知在哪裡能反映出來:( 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2007-02-05 10:56 heqing 想想在什麼地方用到什麼模式,這已經讓我頭暈了. 回複 更多評論
# C#設計模式(5)[TrackBack] 2007-02-09 14:52 Sean(陳陽) C#設計模式(5)-FactoryMethodPattern 一、 查看原文 回複 更多評論
# re: C#設計模式(5)-Factory Method Pattern 2007-02-13 10:56 Cameo 寫的不錯,我們公司的架構主要是用到了Factory 方法模式 回複 更多評論
# C#設計模式--筆記[TrackBack] 2007-03-06 16:34