前言:從本篇開始談設計模式時應該有好些詞組或者是說法可能是我杜撰的,不過可以顧名思義。我重在用通俗的話和代碼說明我理解的設計模式。
一、簡介
1 . 本質
Factory,工廠設計模式,屬于創建型設計模式之一。它主要做到了實例化對象時用工廠方法代替new操作,將選擇實現類、創建對象進行了的統一管理和控制,從而將調用者和實現類解耦。
2 . 分類
工廠模式分為如下幾類:
(1). Simple Factory(簡單工廠)
又稱為靜態工廠,用來生產同一等級結構中的任意產品。對于增加新的產品,需要修改已有的代碼,違反了OCP(開閉原則)。
(2). Factory Method(工廠方法)
用來生產同一等級結構中的固定產品,支持增加任意產品。
(3). Abstract Factory(抽象工廠)
用來生產不同產品族的全部產品,不過對于增加新的產品無能為力,只能是增加產品族。
二、問題引入
既然是工廠設計模式,我們就以造汽車的工廠為例。汽車工廠可以造BMW、BYD等汽車。
首先我們來看看沒有工廠模式的情形。
1. 代碼結構如下:
其中Car為接口,BMW和BYD均為Car的實現類
public interface Car { public void run();}
public class BYD implements Car{ @Override public void run() { System.out.println("BYD is running"); }}
public class BMW implements Car { @Override public void run() { System.out.println("BMW is running"); }}
現在調用者要創建BMW和BYD對象了
public class TestNoFactory { public static void main(String[] args) { Car c1 = new BYD(); Car c2 = new BMW(); c1.run(); c2.run(); }}
2 . 分析上述的UML圖
后面所畫的UML都是用的IDE畫的,方法見上篇blog。
3. 問題來了
這里將TestNoFactory稱之為調用者,那么這里想要去調用BYD和BMW的run方法,則既需要知道Car,還需要知道BYD和BMW類。需要知道的太多對調用者來說并不是什么好事,因此要引入下面的SimpleFactory來解決。
三、SimpleFactory(簡單工廠)代碼結構
同樣的,Car為接口,BMW和BYD均為Car的實現類,代碼同上。如下為CarFactory.java的實現代碼。
public class CarFactory { public static Car createBMW() { return new BMW(); } public static Car createBYD() { return new BYD(); }}
當然CarFactory類里的createXX方法實現邏輯可以自己寫,比如說寫成如下if-else
public class CarFactory { public static Car createCar(String carBrand) { if ("BYD".equals(carBrand)) { return new BYD(); } else if ("BMW".equals(carBrand)) { return new BMW(); } else { return null; } }}
再來看看調用者是如何調用的。
public class TestSimpleFactory { public static void main(String[] args) { Car c1 = CarFactory.createCar("BYD"); Car c2 = CarFactory.createCar("BMW"); c1.run(); c2.run(); }}
2 . UML圖分析
3. 問題來了
經過分析可以知道,調用者TestSimpleFactory只需要Car和CarFactory就可以造出BMW和BYD,解決了沒有factory時“需要知道太多”的問題。但是,也存在這么一個問題,試想如果要增加Ford汽車類,那么除了增加Ford類的代碼外,還得修改CarFactory類的代碼。違反了OCP(開閉原則)。下面再看看FactoryMethod方法是如何解決的OCP問題的。
四、FactoryMethod(工廠方法)代碼結構
CarFactory現在也是接口,BYDFactory類和BMWFactory類均為CarFactory的實現類。
public interface CarFactory { public Car ceateCar(); }
public class BYDFactory implements CarFactory { @Override public Car ceateCar() { return new BYD(); }}
public class BMWFactory implements CarFactory { @Override public Car ceateCar() { return new BMW(); }}
再來看看調用者。
public class TestFactoryMethod { public static void main(String[] args) { Car c1 = new BYDFactory().ceateCar(); Car c2 = new BMWFactory().ceateCar(); c1.run(); c2.run(); }}
2 . UML圖
3 . 問題來了
工廠方法解決了simpleFactory不滿足OCP原則。在工廠方法中如果需要擴展一個Ford汽車類,那么只需要創建一個Ford類和一個FordFactory類,而不需要去動其他的類。
但是存在這樣一個問題:相對于simpleFactory來說,FactoryMethod增加了更多的類。其實在simpleFactory下也是可以做到增加類的,比如說在CarFactory中繼續增加方法,只是這樣做就會因為增加一個類還去改變了另外一個類(違反OCP)。所以可以這么理解吧,FactoryMethod以犧牲更多的類來彌補SimpleFactory違反OCP的問題。
兩種模式的采取依具體而定吧,項目開發中可能simpleFactory更多。
五、AbstractFactory(抽象工廠)
這是用來生產產品族的模式,可能跟上面的兩種方法不能做到很好的承上啟下,我這里只是把這種思維盡量的表述清楚而已。
1 . 代碼結構
其中CarFactory為接口,LowCarFactory和LuxuryCarFactory為實現CarFactory的實現類;MyEngine、MySeat、MyTyre也為接口,Luxury(low)Seat、Luxury(low)Engine、Luxury(Low)Tyre均為實現他們的類。
2 . 模型通俗化
看到上面的代碼結構也就知道AbstractFactory是比較復雜的了。這些代碼其實是在解決這么一個問題。我們都知道CarFactory是用來造汽車的,但是汽車也是有高低檔(Luxury/Low)之分的,那么他們的高低檔提現在哪里呢?體現在造車用的零配件,高檔汽車就用高檔的零件,低檔就用低檔的零件,因此就需要演化出等級結構,比如說生產發動機的等級結構,既生產高檔的發動機,又生產低檔的發動機;比如說生產輪胎的等級,即生產高檔的輪胎也生產低檔的輪胎……因此就需要抽象出MyEngine、MyTyre等接口用來生產。
/** * 發動機:分為高端和低端發動機 * @author herdyouth * */public interface MyEngine { public void run(); public void start();}
當有了不同檔次的零件之后,高端工廠就利用高端的零件組裝高端的汽車,低端工廠就利用低端的零件組裝低端的汽車,高端汽車和低端汽車就稱之為產品族,而能生產(組裝)出完整的高低端汽車的地方就是一個具體的工廠。
public class LuxuryCarFactory implements CarFactory { @Override public MyEngine createEngine() { return new LuxuryEngine(); } @Override public MySeat createSeat() { return new LuxurySeat(); } @Override public MyTyre createTyre() { return new LuxuryTyre(); }}
public class LowCarFactory implements CarFactory { @Override public MyEngine createEngine() { return new LowEngine(); } @Override public MySeat createSeat() { return new LowSeat(); } @Override public MyTyre createTyre() { return new LowTyre(); }}
再來看看調用者如何獲取高/低檔汽車的。
public class TestAbstractFactory { public static void main(String[] args) { CarFactory factory = new LuxuryCarFactory(); MyEngine e = factory.createEngine(); e.start(); e.run(); }}
抽象出這樣一個理解模型(這是在網上找的一個,還比較貼切),一種形狀代表一種類型的產品,比如矩形都是發動機。
3 . 問題來了
有上分析知道,AbstractFactory對于增加單個新產品是無能為力的,只能新增加產品族,因為你增加單個產品就意味著得修改已有的類,違反OCP,而你增加新的產品族,就只是將已有的產品組合一下,比如說一個高檔的發動機配上低檔的輪胎等組成中檔汽車族。
六、有了對比也沒有傷害
每種方式來的最后我都做了“問題來了”的分析,即是一種對比。下面稍微“官方”或者說更抽象一點來PK一下。
1. 簡單工廠模式和工廠方法模式
(1). 結構復雜度
從上面的代碼結構分析知道,簡單工廠沒有工廠方法復雜,因為簡單工廠只是需要增加一個類,而工廠方法是要增加一個相應的接口和實現類的。
(2). 代碼復雜度
結構復雜度和代碼復雜度是相反的。從UML圖知道,工廠方法需要知道的更少。
(3). 管理難度
工廠方法模式完全滿足OCP,即具有良好的擴展性。但是并不是說簡單工廠方法因為不完全滿足OCP就不舉有良好的擴展性,簡單工廠在擴展的時候其實也是只需要改動其他類的少量代碼的。根據設計理論建議,是建議用工廠方法模式,但實際中一般都用的簡單工廠模式,不要太拘泥于設計理論,據說jdk中也有很多沒有完全滿足OCP的例子。
2. 情形建議
適合使用工廠模式的情形:
(1). 有一組類似的對象需要創建;
(2). 在編碼時不能預見需要創建哪種類的實例;
(3). 系統需要考慮擴展性,不應依賴于產品類實例如何被創建、組合和表達的細節
3. Factory模式要點總結
(1) . 簡單工廠(靜態工廠)
雖然某種程度上不符合設計原則,但實際使用最多。
(2). 工廠方法
完全符合OCP,在不修改已有類的前提下,通過增加新的工廠類實現擴展。
(3). 抽象工廠
不可以增加產品,但是可以增加產品族。
示例代碼:https://github.com/herdyouth/DesignPatterns_Factory
=====================無聊分割線=================
GOF確實是一種很高的境界,我這里只是談談我的理解,可能存在問題的,希望能相互探討。
就愛閱讀www.92to.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20161102/32993.html
文章列表