標籤:

設計模式之工廠模式

題外話:本文的代碼我放在 Github 上,感興趣的可以去下載使用。

下面介紹三種設計模式,簡單工廠模式,工廠方法模式,抽象工廠模式。

工廠方法模式和抽象工廠模式屬於 23 種設計模式之中,均屬於創建類模式。

思考如下場景:

有一天,林同學準備去買筆記本,他到商城發現有兩款電腦他特別喜歡, 一款是 Macbook Pro, 另一款是 Surface Pro。

根據以上的場景,類圖可以如下表示:

interface Computer {n public void printComputer();n}nnclass MacbookProComputer implements Computer {n public void printComputer() {n System.out.println("This is a macbook pro");n }n}nnclass SurfaceBookComputer implements Computer {n public void printComputer() {n System.out.println("This is a surface book");n }n}nnpublic class Client {n public void buy(Computer c){n c.printComputer();n }n public static void main(String[] args) {n Client c = new Client();n c.buy(new SurfaceBookComputer());n }n}n

這時候問題就來了,客戶只關心得到電腦,並不關心電腦是如何被生產出來的,假設這裡電腦是由滑鼠,鍵盤和顯示器組成,那麼我們還需要先創建這些類實例,才能創建電腦。

Keyboard keyboard = new Keyboard();nDisplay display = new Display();nMouse mouse = new Mouse();nClient c = new Client();nc.buy(new SurfaceBookComputer(keyboard, display, mouse));n

顯然商家在賣電腦的時候不會要求客戶自己把電腦組裝好的吧。

簡單工廠模式

下面就先介紹簡單工廠模式。

簡單工廠模式:專門定義一個類用來創建其它類的實例,被創建的實例通常都具有共同的父類。

這裡我們相當於是創建生產電腦的工廠,客戶需要購買什麼樣的電腦,只要輸入類型編號就可以獲取該電腦,而無需知道該電腦是如何被生產出來的。

類圖如下表示:

Java 代碼:

interface Computer {n public void printComputer();n}nnclass MacbookProComputer implements Computer {n public void printComputer() {n System.out.println("This is a macbook pro");n }n}nnclass SurfaceBookComputer implements Computer {n public void printComputer() {n System.out.println("This is a surface book");n }n}nnclass ComputerFactory {n public Computer createComputer(String type) {n Computer c = null;n if(type.equals("macbook")) {n c = new MacbookProComputer();n }else if(type.equals("surface")) {n c = new SurfaceBookComputer();n }n return c;n }n}nnpublic class Client {n public void buy(Computer c){n System.out.println("I buy a computer");n c.printComputer();n }n public static void main(String[] args) {nn Client c = new Client();n ComputerFactory cf = new ComputerFactory();nn Computer computer = cf.createComputer("macbook");n c.buy(computer);n }n}n

工廠模式的角色一般包括:

  1. 工廠角色: 如上圖的 ComputerFactory,它可以被客戶端調用,其內部用於負責創建具體的對象。
  2. 抽象產品類:如上圖的 Computer,它描述了所有實例的公共介面。
  3. 具體產品類:如上圖的 MacbookProComputer,實現抽象產品的介面,是工廠角色中要創建的具體實例。

簡單工廠模式的優點從上面兩種方式對比可以看出,工廠角色負責產生具體的實例對象,所以在工廠類中需要有必要的邏輯,通過客戶的輸入能夠得到具體創建的實例;所以客戶端就不需要感知具體對象是如何產生的,只需要將必要的信息提供給工廠即可。

這時候負責這個工廠的產品經理說該工廠需要生產新的產品 Macbook Air, 那麼該方法的缺點就暴露顯現,一般工廠生產方法和具體產品實現一般是由不同工程師開發的,那麼如果實現產品的工程師早早實現了新產品而工廠方法卻一直沒有更新,那麼該產品就一直無法上架。其次代碼耦合度太高,如果工廠方法由新來的工程師去修改的話,那麼他又得先讀懂源代碼,效率顯得低下。

所以簡單工廠模式的缺點:簡單工廠模式是違反「開閉原則」,即對擴展開放,對修改關閉;因為如果要新增具體產品,就需要修改工廠類的代碼。

針對簡單工廠模式暴露出來的弊端,我們需要對代碼再進行改進,由此延伸出工廠方法模式。

工廠方法模式

工廠方法模式:定義一個用來創建對象的介面,讓子類決定實例化哪一個類,讓子類決定實例化延遲到子類。

工廠方法模式是針對每個產品提供一個工廠類,在客戶端中判斷使用哪個工廠類去創建對象。

我們將之前的 ComputerFactory 抽象成一個介面,那麼創建相應具體的工廠類去實現該介面的方法。

具體類圖的實現:

Java 代碼實現:

interface Computer {n public void printComputer();n}nnclass MacbookProComputer implements Computer {n public void printComputer() {n System.out.println("This is a macbook pro");n }n}nnclass SurfaceBookComputer implements Computer {n public void printComputer() {n System.out.println("This is a surface book");n } n}ninterface ComputerFactory {n public Computer createComputer();n}nnclass MsFactory implements ComputerFactory {n public Computer createComputer(){n return new SurfaceBookComputer();n }n}nnclass AppleFactory implements ComputerFactory {n public Computer createComputer() {n return new MacbookProComputer();n }n}nnpublic class Client {n public void buy(Computer c){n System.out.println("I buy a computer");n c.printComputer();n }n public static void main(String[] args) {nn Client c = new Client();n ComputerFactory cf = new AppleFactory();nn Computer computer = cf.createComputer();n c.buy(computer);n }n}n

工廠方法模式是針對每個產品提供一個工廠類,在客戶端中判斷使用哪個工廠類去創建對象。

對比簡單工廠模式和工廠方法模式:

對於簡單工廠模式而言,創建對象的邏輯判斷放在了工廠類中,客戶不感知具體的類,但是其違背了開閉原則,如果要增加新的具體類,就必須修改工廠類。

對於工廠方法模式而言,是通過擴展來新增具體類的,符合開閉原則,但是在客戶端就必須要感知到具體的工廠類,也就是將判斷邏輯由簡單工廠的工廠類挪到客戶端。

工廠模式橫向擴展很方便,假如該工廠又有新的產品 Macbook Air 要生產,那麼只需要創建相應的工廠類和產品類去實現抽象工廠介面和抽象產品介面即可,而不用去修改原有已經存在的代碼。

抽象工廠模式:

這時候負責該工廠的產品經理說要生產新的一類產品操作系統 Mac Os 和 Windows 8,這時候就引申出了抽象工廠模式。

抽象工廠模式:提供一個創建一系列相關或相互依賴對象的介面,而無需指定它們具體的類。

工廠方法模式和抽象工廠模式基本類似,可以這麼理解:當工廠只生產一個產品的時候,即為工廠方法模式,而工廠如果生產兩個或以上的商品即變為抽象工廠模式。

我們在抽象工廠介面中新增創建系統的方法,並由實例工廠類去實現。

類圖可由下表示:

interface Computer {n public void printComputer();n}nnclass MacbookProComputer implements Computer {n public void printComputer() {n System.out.println("This is a macbook pro");n }n}nnclass SurfaceBookComputer implements Computer {n public void printComputer() {n System.out.println("This is a surface book");n }n}nninterface OperatingSystem {n public void printSystem();n}nnclass MacOsSystem implements OperatingSystem {n public void printSystem() {n System.out.println("This is a mac os");n }n}nnclass Windows8System implements OperatingSystem {n public void printSystem() {n System.out.println("This is a window 8");n }n}nninterface ProductionFactory {n public Computer createComputer();n public OperatingSystem createSystem();n}nnclass AppleFactory implements ProductionFactory {n public Computer createComputer() {n return new MacbookProComputer();n }n public OperatingSystem createSystem() {n return new MacOsSystem();n }n}nnclass MsFactory implements ProductionFactory {n public Computer createComputer() {n return new SurfaceBookComputer();n }n public OperatingSystem createSystem() {n return new Windows8System();n }n}nnpublic class Client {nn public void buy(Computer c){n System.out.println("I buy a computer");n c.printComputer();n }n public void use(OperatingSystem s) {n System.out.println("Operating System");n s.printSystem();n }n public static void main(String[] args) {ntn ProductionFactory pf = new AppleFactory();n Computer c = pf.createComputer();n OperatingSystem s = pf.createSystem();nn Client client = new Client();n client.buy(c);n client.use(s);nn }n}n

抽象工廠模式的缺點在於產品類的擴展,將會是十分費力的,假如在需要加入新的產品,那麼幾乎所有的工廠類都需要進行修改,所以在使用抽象工廠模式時,對產品等級結構的劃分是十分重要的。

適用場景:

無論是簡單工廠模式,工廠方法模式還是抽象工廠模式,它們都具有類似的特性,適用場景也十分類似。

無論是簡單工廠模式,工廠方法模式,還是抽象工廠模式,他們都屬於工廠模式,在形式和特點上也是極為相似的,他們的最終目的都是為了解耦。在使用時,我們不必去在意這個模式到底工廠方法模式還是抽象工廠模式,因為他們之間的演變常常是令人琢磨不透的。經常你會發現,明明使用的工廠方法模式,當新需求來臨,稍加修改,加入了一個新方法後,由於類中的產品構成了不同等級結構中的產品族,它就變成抽象工廠模式了;而對於抽象工廠模式,當減少一個方法使的提供的產品不再構成產品族之後,它就演變成了工廠方法模式。

所以,在使用工廠模式時,只需要關心降低耦合度的目的是否達到了。使用工廠方法後,調用端的耦合度大大降低了。並且對於工廠來說,是可以擴展的,以後如果想組裝其他的產品,只需要再增加一個工廠類的實現就可以。無論是靈活性還是穩定性都得到了極大的提高。

推薦閱讀:

PyQt信號槽的Python實現
Design Pattern 劃分方式是對設計的邏輯思考
編寫可維護代碼之「中間件模式」
一種Python全局配置規範以及其魔改
【遊戲設計模式】之三 狀態模式、有限狀態機 & Unity版本實現

TAG:设计模式 |