——.NET設計模式系列之七
Terrylee
,
2006
年
1
月
概述
創建型模式,就是用來創建對象的模式,抽象了實例化的過程。它幫助一個系統獨立于如何創建、組合和表示它的那些對象。本文對五種常用創建型模式進行了比較,通過一個游戲開發場景的例子來說該如何使用創建型模式。
為什么需要創建型模式
所有的創建型模式都有兩個永恒的主旋律:第一,它們都將系統使用哪些具體類的信息封裝起來;第二,它們隱藏了這些類的實例是如何被創建和組織的。外界對于這些對象只知道它們共同的接口,而不清楚其具體的實現細節。正因如此,創建型模式在創建什么(
what
),由誰(
who
)來創建,以及何時(
when
)創建這些方面,都為軟件設計者提供了盡可能大的靈活性。
假定在一個游戲開發場景中,會用到一個現代風格房屋的對象,按照我們的一般想法,既然需要對象就創建一個:
ModernRoom room
=
new
ModernRoom();
好了,現在現代風格房屋的對象已經有了,如果這時房屋的風格變化了,需要的是古典風格的房屋,修改一下:
Classical
Room room
=
new
Classical
Room();
試想一下,在我們的程序中有多少處地方用到了這樣的創建邏輯,而這里僅僅是房屋的風格變化了,就需要修改程序中所有的這樣的語句。現在我們封裝對象創建的邏輯,把對象的創建放在一個工廠方法中:
ModernFactory factory
=
new
ModernFactory();
ModernRoom room
=
factory
.
Create();
當房屋的風格變化時,只需要修改
Classical
Factory factory
=
new
Classical
Factory();
Classical
Room room
=
factory
.
Create();
而其它的用到
room
的地方仍然不變。這就是為什么需要創建型模式了。創建者模式作用可以概括為如下兩點:
1
.封裝創建邏輯,絕不僅僅是
new
一個對象那么簡單。
2
.封裝創建邏輯變化,客戶代碼盡量不修改,或盡量少修改。
常見的五種創建型模式
單件模式
(
Singleton Pattern
)解決的是實體對象的個數問題,其他的都是解決
new
所帶來的耦合關系問題。
工廠方法模式
(
Factory Pattern
)在工廠方法中,工廠類成為了抽象類,其實際的創建工作將由其具體子類來完成。工廠方法的用意是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類中去,強調的是“單個對象”的變化。
抽象工廠模式
(
Abstract Factory
)抽象工廠是所有工廠模式中最為抽象和最具有一般性的一種形態。抽象工廠可以向客戶提供一個接口,使得客戶可以在不必指定產品的具體類型的情況下,創建多個產品族中的產品對象,強調的是“系列對象”的變化。
生成器模式
(
Builder Pattern
)把構造對象實例的邏輯移到了類的外部,在這個類的外部定義了這個類的構造邏輯。他把一個復雜對象的構造過程從對象的表示中分離出來。其直接效果是將一個復雜的對象簡化為一個比較簡單的目標對象。他強調的是產品的構造過程。
原型模式
(
Prototype Pattern
)和工廠模式一樣,同樣對客戶隱藏了對象創建工作,但是,與通過對一個類進行實例化來構造新對象不同的是,原型模式是通過拷貝一個現有對象生成新對象的。
如何選擇使用創建型模式
繼續考慮上面提到的游戲開發場景,假定在這個游戲場景中我們使用到的有墻(
Wall
),屋子(
Room
),門(
Door
)幾個部件。在這個過程中,同樣是對象的創建問題,但是會根據所要解決的問題不同而使用不同的創建型模式。
如果在游戲中,一個屋子只允許有一個門存在,那么這就是一個使用
Signleton
模式的例子,確保只有一個
Door
類的實例被創建。解決的是對象創建個數的問題。
示例代碼:
using
System;
public
sealed
class
SigletonDoor
{
static
readonly
SigletonDoor instance
=
new
SigletonDoor();
static
SigletonDoor()
{
}
public
static
SigletonDoor Instance
{
get
{
return
instance;
}
}
}
在游戲中需要創建墻,屋子的實例時,為了避免直接對構造器的調用而實例化類,這時就是工廠方法模式了,每一個部件都有它自己的工廠類。解決的是“單個對象”的需求變化問題。
示例代碼:
using
System;
public
abstract
class
Wall
{
public
abstract
void
Display();
}
public
class
ModernWall:Wall
{
public
override
void
Display()
{
Console
.
WriteLine(
"ModernWall Builded"
);
}
}
public
abstract
class
WallFactory
{
public
abstract
Wall Create();
}
public
class
ModernFactory:WallFactory
{
public
override
Wall Create()
{
return
new
ModernWall();;
}
}
在游戲場景中,不可能只有一種墻或屋子,有可能有現代風格(
Modern
),古典風格(
Classical
)等多系列風格的部件。這時就是一系列對象的創建問題了,是一個抽象工廠的例子。解決的是“系列對象”的需求變化問題。
示例代碼:
using
System;
public
abstract
class
Wall
{
public
abstract
void
Display();
}
public
class
ModernWall:Wall
{
public
override
void
Display()
{
Console
.
WriteLine(
"ModernWall Builded"
);
}
}
public
class
ClassicalWall:Wall
{
public
override
void
Display()
{
Console
.
WriteLine(
"ClassicalWall Builded"
);
}
}
public
abstract
class
Room
{
public
abstract
void
Display();
}
public
class
ModernRoom:Room
{
public
override
void
Display()
{
Console
.
WriteLine(
"ModernRoom Builded"
);
}
}
public
class
ClassicalRoom:Room
{
public
override
void
Display()
{
Console
.
WriteLine(
"ClassicalRoom Builded"
);
}
}
public
abstract
class
AbstractFactory
{
public
abstract
Wall CreateWall();
public
abstract
Room CreateRoom();
}
public
class
ModernFactory:AbstractFactory
{
public
override
Wall CreateWall()
{
return
new
ModernWall();
}
public
override
Room CreateRoom()
{
return
new
ModernRoom();
}
}
public
class
ClassicalFactory:AbstractFactory
{
public
override
Wall CreateWall()
{
return
new
ClassicalWall();
}
public
override
Room CreateRoom()
{
return
new
ClassicalRoom();
}
}
如果在游戲場景中,構成某一個場景的算法比較穩定,例如:這個場景就是用四堵墻,一個屋子,一扇門來構成的,但具體是用什么風格的墻、屋子和門則是不停的變化的,這就是一個生成器模式的例子。解決的是“對象部分”的需求變化問題。
示例代碼:
using
System;
using
System
.
Collections;
public
class
Director
{
public
void
Construct( Builder builder )
{
builder
.
BuildWall();
builder
.
BuildRoom();
builder
.
BuildDoor();
}
}
public
abstract
class
Builder
{
public
abstract
void
BuildWall();
public
abstract
void
BuildRoom();
public
abstract
void
BuildDoor();
public
abstract
GameScene GetResult();
}
public
class
GameBuilder : Builder
{
private
GameScene g;
public
override
void
BuildWall()
{
g
=
new
GameScene();
g
.
Add(
"Wall"
);
}
public
override
void
BuildRoom()
{
g
.
Add(
"Room"
);
}
public
override
void
BuildDoor()
{
g
.
Add(
"Door"
);
}
public
override
GameScene GetResult()
{
return
g;
}
}
public
class
GameScene
{
ArrayList parts
=
new
ArrayList();
public
void
Add(
string
part )
{
parts
.
Add( part );
}
public
void
Display()
{
Console
.
WriteLine(
" GameScene Parts
:"
);
foreach
(
string
part
in
parts )
Console
.
WriteLine( part );
}
}
如果在游戲中,需要大量的古典風格或現代風格的墻或屋子,這時可以通過拷貝一個已有的原型對象來生成新對象,就是一個原型模式的例子了。通過克隆來解決“易變對象”的創建問題。
示例代碼:
using
System;
public
abstract
class
RoomPrototype
{
public
abstract
RoomPrototype Clone();
}
public
class
ModernPrototype:RoomPrototype
{
public
override
RoomPrototype Clone()
{
return
(RoomPrototype)
this
.
MemberwiseClone();
}
}
public
class
ClassicalPrototype:RoomPrototype
{
public
override
RoomPrototype Clone()
{
return
(RoomPrototype)
this
.
MemberwiseClone();
}
}
究竟選用哪一種模式最好取決于很多的因素。使用
Abstract Factory
、
Prototype Pattern
或
Builder Pattern
的設計比使用
Factory Method
的設計更加靈活,但是也更加復雜,尤其
Abstract Factory
需要龐大的工廠類來支持。通常,設計以使用
Factory Method
開始,并且當設計者發現需要更大的靈活性時,設計便會向其他設計模式演化,當你在多個設計模式之間進行權衡的時候,了解多個設計模式可以給你提供更多的選擇余地。
總結
使用創建者模式是為了提高系統的可維護性和可擴展性,提高應對需求變化的能力!
參考文獻:
《設計模式中文版》
《DesignPatternsExplained》
idior 的《 你了解創建者模式了嗎? --- 創建者模式詳解 》
MSDN WebCast: http://www.microsoft.com/china/msdn/events/webcasts/shared/Webcast/MSDNWebCast.aspx
參考文獻:
《設計模式中文版》
《DesignPatternsExplained》
idior 的《 你了解創建者模式了嗎? --- 創建者模式詳解 》
MSDN WebCast: http://www.microsoft.com/china/msdn/events/webcasts/shared/Webcast/MSDNWebCast.aspx
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
