- 論壇徽章:
- 0
|
呵呵,朋友們好,自從開始寫《用Java實(shí)現(xiàn)的設(shè)計(jì)模式系列》文章以來,發(fā)現(xiàn)自己對于設(shè)計(jì)模式的理解果然比原來好了很多,這可能是因?yàn)橛肑ava來實(shí)現(xiàn)設(shè)計(jì)模式更為貼切和易理解的原因吧。在寫這些系列文章時(shí),俺當(dāng)然參考了網(wǎng)上其它前輩們的源碼,對俺最有幫助的就是那本Design Patter In Java,寫得很不錯(cuò),但可惜,里面的例子,俺還是覺得有點(diǎn)復(fù)雜。按我的想法,既然設(shè)計(jì)模式這么難學(xué),所以,剛開始時(shí),對于設(shè)計(jì)模式的應(yīng)用,我們只要盡量抓住每個(gè)模式最本質(zhì)的地方,并力求代碼盡量簡單易懂就好了。至于等到日后你正確理解了設(shè)計(jì)模式,再去搞復(fù)雜的代碼也不遲。也許,就是因?yàn)楫?dāng)初自己學(xué)設(shè)計(jì)模式學(xué)得太苦,所以不希望大家再走我一樣的彎路,因此也就有了這個(gè)系列文章。希望自己的這個(gè)用Java實(shí)現(xiàn)的設(shè)計(jì)模式系列能真正對大家有所幫助。當(dāng)然,也希望自己能全部寫完(呵呵。。先給自己加點(diǎn)勁)。
好了,言歸正傳,讓我們來看看今天的主角----Builder,中文又叫做生成器。
當(dāng)初我學(xué)這個(gè)設(shè)計(jì)模式的時(shí)候,怎么都搞不懂它和工廠模式到底有什么區(qū)別,而且看了很多別人實(shí)現(xiàn)的源代碼,似乎都是在模仿工廠模式的實(shí)現(xiàn)。并沒有突出Builder與Factory的本質(zhì)差別。實(shí)際上,就我的理解,既然Builder和Factory同屬創(chuàng)建型模式,那么他們的最大共同點(diǎn)就在于都可以創(chuàng)建類對象,在這點(diǎn)上,不光這兩個(gè)模式一樣,其它創(chuàng)建型模式也一樣。但正如我在《深入探索Factory模式與Prototype模式的異同(續(xù))》一文中所說,這些模式,功能上的相似,只是“形似而非神似”。既然這樣,那好,下面就讓我們能看看Builder和Factory在功能的相似上,存在哪些神韻方面的差別。
首先,也是最重要的一點(diǎn),就是雖然Builder和Factory都可創(chuàng)建產(chǎn)品,但兩者所創(chuàng)建的產(chǎn)品類型完全不一樣。Factory創(chuàng)建只能是單一的產(chǎn)品(單一在這指它非復(fù)合產(chǎn)品),而Builder所創(chuàng)建的產(chǎn)品是復(fù)合產(chǎn)品,即產(chǎn)品本身就是由其它部件產(chǎn)品組成的。舉個(gè)例子來說,現(xiàn)在要生產(chǎn)一輛車,假設(shè)它就只由這三個(gè)部分組成:玻璃、輪子、發(fā)動機(jī)。對于工廠模式來說,他創(chuàng)建后返回的,只能是玻璃,或者輪子,抑或是發(fā)動機(jī)。不管怎么樣,他不能向客戶返回一輛完整的汽車,要得到一輛完整的汽車,客戶必須自己動手去把這些零部件組裝成一輛汽車。從這個(gè)意義上來講,工廠模式中的工廠,只是充當(dāng)了零件廠的角色。那Builder又是如何創(chuàng)建產(chǎn)品的呢?在Builder模式中,一般不需要、也不充許向客戶返回單個(gè)部件,他向客戶返回的,僅僅就是一部已經(jīng)完全組裝好的汽車成品。對于汽車部件的生產(chǎn)細(xì)節(jié),客戶不需要、也不應(yīng)該讓他們知道。寫到這,我突然想到了組裝電腦與品牌電腦的差別,組裝電腦雖然價(jià)格便宜,且易于改動,但性能沒有保證,另外你自己還必須了解很多有關(guān)電腦方面的知識;對于品牌電腦,價(jià)格貴這點(diǎn)先暫時(shí)不說,關(guān)鍵在于他不靈活,但是它的性能可以得到很好保證(由廠家),這易像我們在Builder的系統(tǒng)端保證部件的質(zhì)量一樣。另外,對于品牌電腦,客戶根本不需要了解多少電腦組裝方面的知識,就可以把一臺電腦抱回家,開機(jī)使用了。那么,在實(shí)際運(yùn)用中,你是喜歡做DIY一族呢,還是喜歡穩(wěn)定有保證的質(zhì)量呢?好像在我們編著程的這個(gè)過程中,我們比較趨向于使用“品牌電腦”。這也就為我們正確使用這兩種設(shè)計(jì)模式提供了一個(gè)方向:如果你要生產(chǎn)的產(chǎn)品是由不同部件組成的,你最好使用Builder模式,而非Factory模式。
另外,Builder和Factory的差別,就在于他們所生產(chǎn)部件產(chǎn)品所在產(chǎn)品樹的問題。這樣說,可能有點(diǎn)拗口。具體來說吧,在工廠模式中,我們知道,一個(gè)工廠可以創(chuàng)建多個(gè)產(chǎn)品,但一個(gè)工廠模式中所創(chuàng)建的某個(gè)產(chǎn)品,都會和另一個(gè)工廠中所創(chuàng)建的產(chǎn)品在同一棵繼承樹上。如果大家看過我最早寫的《用Java實(shí)現(xiàn)的設(shè)計(jì)模式系列(1)—Factory 》那篇文章,就會記得,我在CFactoryMac中創(chuàng)建了一種產(chǎn)品叫MacRam,而在CFactoryWin中創(chuàng)建了另一種產(chǎn)品叫WinRam,很顯然,這兩種產(chǎn)品是在同一棵繼承樹上的。對于它們之所以會出現(xiàn)在同一棵繼承樹上,是完全由Factory模式本身所決定的。大家如果看過Factory的UMl圖,就應(yīng)該記得,要實(shí)現(xiàn)Factory模式,一定要有一個(gè)Abstract Product類,具體產(chǎn)品再由它派生出來。好了,說完了Factory,再讓我們來看看Builder中是否必這么做!實(shí)際上,在Builder模式中,我們只是在Abstract Builder中封裝了創(chuàng)建部件的接口,而具體創(chuàng)建了什么部件,不同的實(shí)際Builder可能會生產(chǎn)出完全不一樣的部件,這樣不會存在任何問題,因?yàn),我上面說過,Builder只是向客戶返回成品,而不向客戶返回具體部件,這樣,當(dāng)然就充許產(chǎn)品的部件按要求隨意變化了。再舉個(gè)例子吧,假如你現(xiàn)在要創(chuàng)建兩種風(fēng)馬不相及的東西,例如一種是人,它就只由這幾部分組成:腦、身、四肢;另一種是樹,也由三個(gè)部分組成:根、葉、莖。好了,你現(xiàn)在要用Builder模式創(chuàng)建出這兩種產(chǎn)品,能不能做到呢?看看下面的代碼就明白了:
interface ABuilder{
public void builderPartA();
public void builderPartB();
public void builderPartC();
}
class CBuilderHuman implements ABuilder {
private Human human;
public CBuilderHuman() {
human=new Human();
}
public void builderPartA(){human.head=new Head()};
public void builderPartB(){human.body=new Body()};
public void builderPartC()(human.limb=new Limb()};
public Human getProduct(){
builderPartA();
builderPartB();
builderPartC();
return human;
}
class CBuilderTree的代碼類似,這里就不寫了。
再來看客戶端代碼:
public stacic void main(String[] args) {
CBuilderHuman builderhuman=new CBuilderHuman();
CBuilderTree buildertree=new CBuilderTree();
Human man;
Tree tree;
man=builderman.getProduct();
tree=buildertree.getProduct();
}
看了上面的代碼,相信大家對于Factory與Builder的產(chǎn)品樹問題已有了清楚的認(rèn)識。雖然,Builder模式可以創(chuàng)建出風(fēng)馬不相及的產(chǎn)品,但一般我們不會這么做。更常見的運(yùn)用是部件產(chǎn)品在同一棵繼承樹上。這樣做的原因,大家想想面向?qū)ο蟮谋举|(zhì)目的也就明白了。
好了,隨手寫寫,想不到就寫了這么一大篇。還是那句話,代碼說明一切,那接下來,就讓我們來看代碼吧!
/**
* Design Pattern In Java
* Name:Builder
* 目的:利用Builder模式創(chuàng)建兩種汽車carA和carB
* Car=Glass+Wheel+Engine
* carA=AmericanGlass+JapaneseWheel+ChinaEngine
* carB=JapaneseGlass+AmericanWheel+FranceEngine
* A:abstract
* C:Concret
* Author:blackphoenix
* Modify Date:2002-08-19
*/
/**
* 定義部件Glass的抽象類AClass
* 和兩個(gè)具體類AmericanGlass、JapaneseGlass
*/
abstract class AGlass{
}
class AmericanGlass extends AGlass{
public String toString(){
return "\"American Glass\" ";
}
}
class JapaneseGlass extends AGlass{
public String toString(){
return "\"Japanese Glass\" ";
}
}
/**
* 定義部件Wheel的抽象類AWheel
* 和兩個(gè)具體類AmericanWheel、JapaneseWheel
*/
abstract class AWheel{
}
class AmericanWheel extends AWheel{
public String toString(){
return "\"American Wheel\" ";
}
}
class JapaneseWheel extends AWheel{
public String toString(){
return "\"Japanese Wheel\" ";
}
}
/**
* 定義部件Engine的抽象類AEngine
* 和兩個(gè)具體類ChineseEngine、FranceEngine
*/
abstract class AEngine{
}
class ChineseEngine extends AEngine{
public String toString(){
return "\"Chinese Engine\" ";
}
}
class FranceEngine extends AEngine{
public String toString(){
return "\"France Engine\" ";
}
}
/**
* 定義產(chǎn)品類Car
*/
class Car{
AGlass glass;
AWheel wheel;
AEngine engine;
}
/**
* 定義抽象建造器接口ABuilder
*/
interface ABuilder{
public void buildGlass();
public void buildWheel();
public void buildEngine();
}
/**
* 具體建造器類CBuilderCarA
* carA=AmericanGlass+JapaneseWheel+ChineseEngine
*/
class CBuilderCarA implements ABuilder{
private Car product=null;
public CBuilderCarA(){
product=new Car();
}
public void buildGlass(){
product.glass=new AmericanGlass();
}
public void buildWheel(){
product.wheel=new JapaneseWheel();
}
public void buildEngine(){
product.engine=new ChineseEngine();
}
/**
* 將建造部件的工作封裝在getProduct()操作中,主要是為了向客戶隱藏實(shí)現(xiàn)細(xì)節(jié)
* 這樣,具體建造類同時(shí)又起到了一個(gè)Director的作用
*/
public Car getProduct(){
buildGlass();
buildWheel();
buildEngine();
return product;
}
}
/**
* 具體建造器類CBuilderCarB
* carB=JapaneseGlass+AmericanWheel+FranceEngine
*/
class CBuilderCarB implements ABuilder{
private Car product;
public CBuilderCarB(){
product=new Car();
}
public void buildGlass(){
product.glass=new JapaneseGlass();
}
public void buildWheel(){
product.wheel=new AmericanWheel();
}
public void buildEngine(){
product.engine=new FranceEngine();
}
/**
* 將建造部件的工作封裝在getProduct()操作中,主要是為了向客戶隱藏實(shí)現(xiàn)細(xì)節(jié)
* 這樣,具體建造類同時(shí)又起到了一個(gè)Director的作用
*/
public Car getProduct(){
buildGlass();
buildWheel();
buildEngine();
return product;
}
}
/**
* 客戶端代碼,使用Builder創(chuàng)建兩種不同型別的carA和carB
*/
public class Builder{
public static void main(String[] args){
Builder client=new Builder();
Car carA,carB;
CBuilderCarA builderA;
CBuilderCarB builderB;
builderA=new CBuilderCarA();
builderB=new CBuilderCarB();
carA=builderA.getProduct();
carB=builderB.getProduct();
System.out.println("Car A is made by:"+carA.glass+carA.wheel+carA.engine);
System.out.println("Car B is made by:"+carB.glass+carB.wheel+carB.engine);
}
}
本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u2/67175/showart_2143059.html |
|