王雅軒,頊 聰
(大連外國語學院 軟件學院,大連 116044)
Java對象的一般生產(chǎn)方法是用new來創(chuàng)建的,以類Sample為例,如果要創(chuàng)建類Sample的實例對象,只要使用下面的語句即可:
Sample sample=new Sample();
但是,通常在創(chuàng)建類sample的實例時,要做些初始化的工作,比如賦值、查詢數(shù)據(jù)庫等。這好比工廠中的產(chǎn)品在真正出廠交付客戶之前,要做一些出廠設置或配置之類的工作。這時可以使用類Sample的有參構造函數(shù),這樣生成實例就要寫成:
Sample sample=new Sample(參數(shù));
如果創(chuàng)建sample實例時所做的初始化工作不是像賦值這樣簡單的事,可能是很長一段代碼,如果也寫入構造函數(shù)中,這有背于Java的面向對象的封裝和分割的思想,即盡量將長的代碼“切割”成每個小段,再將每個小段“封裝”起來。這樣,可以減少段與段之間的偶合性。以后如果需要修改,只要更改每個局部段即可,而不會對整體中的其他部分產(chǎn)生影響,即不會發(fā)生牽一發(fā),而動全身的事情。
如果一個系統(tǒng)中存在的類較多,而且在編碼時不能預見需要創(chuàng)建哪一個類的實例,即需要根據(jù)一定的條件,來進行選擇性地創(chuàng)建對象時,用一般的生產(chǎn)方法實現(xiàn)起來也比較困難。
開發(fā)人員不希望創(chuàng)建了哪個類的實例以及如何創(chuàng)建實例的信息暴露給外部程序。
由于上述問題,我們需要將創(chuàng)建實例的工作與使用實例的工作分開, 也就是說,使創(chuàng)建實例所需要的大量初始化工作從類的構造函數(shù)中分離出去,因此我們提出了工廠模式,在工廠模式中,我們就可以把這些復雜的初始化工作,或選擇性地生產(chǎn)產(chǎn)品的方法,或產(chǎn)品族的選擇都可以寫進工廠中。
1)簡單工廠模式(Simple Factory)
簡單工廠模式又稱靜態(tài)工廠方法模式[1],它把大量具有共同接口的類的實例化的過程都封裝到了一個簡單工廠類里了。它實現(xiàn)了對象的創(chuàng)建的過程與客戶端的相互分離(即將創(chuàng)建對象的具體過程屏蔽隔離起來了),從而避免了客戶端與產(chǎn)品類的直接耦合關系。
2)多型工廠模式(Factory Method)
Factory Method是一種創(chuàng)建性模式,它定義了一個創(chuàng)建對象的接口,但是卻讓子類來決定具體實例化哪一個類.當一個類無法預料要創(chuàng)建哪種類的對象或是一個類需要由子類來指定創(chuàng)建的對象時我們就需要用到Factory Method 模式了。簡單地說,F(xiàn)actory Method可以根據(jù)不同的條件產(chǎn)生不同的實例,當然這些不同的實例通常是屬于相同的類型,具有共同的父類。Factory Method把創(chuàng)建這些實例的具體過程封裝起來了,簡化了客戶端的應用,也改善了程序的擴展性,使得將來可以做最小的改動就可以加入新的待創(chuàng)建的類。
3)工具箱工廠模式(Abstract Factory)
抽象工廠模式是所有形態(tài)的工廠模式中最為抽象和最具一般性的一種形態(tài)。 抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產(chǎn)品的具體的情況下,創(chuàng)建多個產(chǎn)品族中的產(chǎn)品對象。
在簡單工廠模式中,一個工廠類處于對產(chǎn)品類實例化調用的中心位置上,它決定那一個產(chǎn)品類應當被實例化, 如同一個交通警察站在來往的車輛流中,決定放行那一個方向的車輛向那一個方向流動一樣。

圖1 簡單工廠模式角色示意圖
從圖1我們可以看出簡單工廠模式涉及到工廠類角色、抽象產(chǎn)品角色、具體產(chǎn)品角色三個參與者。
1) 工廠類角色Creator:工廠類在客戶端的直接控制下(Create方法)創(chuàng)建產(chǎn)品對象
2)抽象產(chǎn)品角色Product:定義簡單工廠創(chuàng)建的對象的父類或它們共同擁有的接口。可以是一個類、抽象類或接口。
3) 具體產(chǎn)品角色ConcreteProduct:定義工廠具體加工出的對象。
工廠方法模式是簡單工廠模式的進一步抽象化和推廣,工廠方法模式里不再只由一個工廠類決定那一個產(chǎn)品類應當被實例化,這個決定被交給子類去作[2,3]。

圖2 多型工廠模式角色示意圖
從圖2可以看出工廠方法模式涉及到抽象工廠角色、具體工廠角色、抽象產(chǎn)品角色和具體產(chǎn)品角色四個參與者。
1)抽象工廠角色:是工廠方法模式的核心,它負責定義創(chuàng)建抽象產(chǎn)品對象的工廠方法。抽象工廠不能被外界直接調用,但任何在模式中用于創(chuàng)建產(chǎn)品對象的工廠類都必須實現(xiàn)由它所定義的工廠方法。
2)具體工廠角色:是工廠方法模式的對外接口,它負責實現(xiàn)創(chuàng)建具體產(chǎn)品對象的內部邏輯。具體工廠與應用密切相關,可以被外界直接調用,創(chuàng)建所需要的產(chǎn)品。
3)抽象產(chǎn)品角色:是工廠方法模式所創(chuàng)建的所有對象的父類,它負責描述所有具體產(chǎn)品共有的公共接口。
4)具體產(chǎn)品角色:是工廠方法模式的創(chuàng)建目標,所有創(chuàng)建的對象都是充當這一角色的某個具體類的實例。
抽象工廠模式是所有形態(tài)的工廠模式中最為抽象和最具廣泛性的一種形態(tài),抽象工廠模式是工廠方法模式的進一步擴廣化和抽象化。

圖3 工具箱工廠模式角色示意圖
如圖3所示:當有多個抽象產(chǎn)品角色時,工廠方法模式已經(jīng)不能滿足要求。根據(jù)LSP里氏替換原則,任何接受父類型的地方,都應當能夠接受子類型[4]。因此,實際上系統(tǒng)所需要的,僅僅是類型與這些抽象產(chǎn)品角色相同的一些實例,而不是這些抽象產(chǎn)品的實例。換言之,也就是這些抽象產(chǎn)品的具體子類的實例。工廠類負責創(chuàng)建抽象產(chǎn)品的具體子類的實例。當每個抽象產(chǎn)品都有多于一個的具體子類的時候,工廠角色怎么知道實例化哪一個子類呢?比如每個抽象產(chǎn)品角色都有兩個具體產(chǎn)品。抽象工廠模式提供兩個具體工廠角色,分別對應于這兩個具體產(chǎn)品角色,每一個具體工廠角色只負責某一個產(chǎn)品角色的實例化。每一個具體工廠類只負責創(chuàng)建抽象產(chǎn)品的某一個具體子類的實例。
工廠方法模式和簡單工廠模式在定義上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式可以允許很多實的工廠類從抽象工廠類繼承下來, 從而可以在實際上成為多個簡單工廠模式的綜合,從而推廣了簡單工廠模式。
反過來講,簡單工廠模式是由工廠方法模式退化而來。設想如果我們非常確定一個系統(tǒng)只需要一個實際工廠類, 那么就不妨把抽象工廠類合并到實的工廠類中去。而這樣一來,我們就退化到簡單工廠模式了。
而在抽象工廠模式中,抽象產(chǎn)品可能是一個或多個,從而構成一個或多個產(chǎn)品族。 在只有一個產(chǎn)品族的情況下,抽象工廠模式實際上退化到工廠方法模式。
工廠方法為系統(tǒng)結構提供了非常靈活強大的動態(tài)擴展機制,在需要的時候,只要更換一下具體的工廠方法,系統(tǒng)其他地方無需任何變換,就有可能將系統(tǒng)功能進行改頭換面的變化。
簡單工廠模式是由一個具體的類去創(chuàng)建其他類的實例,父類是相同的,父類是具體的。
工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣做的目的是將類的實例化操作延遲到子類中完成。
抽象工廠模式提供一個創(chuàng)建一系列相關或相互依賴對象的接口,而無須指定他們具體的類。它針對的是有多個產(chǎn)品的等級結構。而工廠方法模式針對的是一個產(chǎn)品的等級結構。
[1] Steven Metsker, William C.Wake 著,龔波,趙彩琳,陳蓓譯.Java設計模式[M].北京:人民郵電出版社.2007.
[2] 閻宏.Java與模式[M]. 北京:電子工業(yè)出版社.2002.
[3] 結城浩.博碩文化譯.設計模式- Java語言中的應用[M].北京: 中國鐵道出版社, 2005.
[4] James W.Cooper 著.王宇,杜琪,杜志秀,譯.Java與設計模式[M].北京:中國電力出版社.2003.