目錄
一、 簡單介紹
實際上我們可能常用的工廠模式只是簡單工廠(靜態方法工廠),嚴格說來這可能只是一種編程優化的習慣,不能說程爲是一種設計模式,但是不管是簡單工廠、工廠方法還是抽象工廠都是爲軟件架構服務的,具體選擇哪一種需要仔細考量,絕對不能爲用而用,不要裝逼裝高深,簡單、易用、易於理解和維護纔是目的。這篇文章對工廠模式進行一個大概的介紹,便於理解記憶
上圖中的工廠方法和抽象工廠都包含了相同的角色,但是在具體的架構中是有所不同的。
二、簡單工廠
簡單工廠,也叫作靜態方法工廠,包含了三個角色工廠類、抽象產品,具體產品,所有的產品都在工廠類類裏面統一初始化,並通過工廠類的靜態方法統一輸出。
通過一個需求來切入。
2.1 新需求,要求根據簡單工廠設計
BMW公司需要造車,包括320和520兩款車型,除了汽車引擎外,其它零件都是自己生產,Engine的生產(很複雜)可以自己生產或者外包,整車從製造到交付客戶的流程設計?
2.2 簡單工廠流程圖
2.3 簡單工廠實例代碼
public interface IBmwEngine {
void fire();
void run();
void stop();
}
public class Bmw320Engine implements IBmwEngine{
@Override
public void fire() {
System.out.println("BMW320, fire!over!");
}
@Override
public void run() {
System.out.println("BMW320, run!over!");
}
@Override
public void stop() {
System.out.println("BMW320, stop!over!");
}
}
public class Bmw520Engine implements IBmwEngine {
@Override
public void fire() {
System.out.println("BMW520, fire!over!");
}
@Override
public void run() {
System.out.println("BMW520, run!over!");
}
@Override
public void stop() {
System.out.println("BMW520, stop!over!");
}
}
public class BmwEngineFactory {
public final static int BMW_320 = 320;
public final static int BMW_520 = 520;
public static IBmwEngine createEngine(int type) {
IBmwEngine engine = null;
switch (type) {
case BMW_320:
engine = new Bmw320Engine();
break;
case BMW_520:
engine = new Bmw520Engine();
break;
}
return engine;
}
}
public class BmwMaker {
/**
* 準備Engine
*/
private IBmwEngine prepareEngine(int typeEngine) {
return BmwEngineFactory.createEngine(typeEngine);
}
public static void main(String[] args) {
BmwMaker maker = new BmwMaker();
IBmwEngine engine = maker.prepareEngine(BmwEngineFactory.BMW_320);
engine.fire();
engine.run();
engine.stop();
}
}
測試結果:
BMW320, fire!over!
BMW320, run!over!
BMW320, stop!over!
2.4 簡單工廠總結
上面代碼是一個很簡單的例子,也十分方便運用到實際工作中,汽車需要發動機,不同型號的發動機作爲被需要的對象,分爲不同的種類,統一通過工廠類創建實例和管理,上面寫的比較簡單,實例的創建過程涉及到諸多方面,這些細節不對外暴露,試想一下如果我們直接在BmwMaker類中new出我們的對象,然後處理各種細節,那麼我們在BmwMaker需要很多邏輯來管理不同實例,這是比較複雜的,但是如果通過工廠統一處理,那麼BmwMaker只需要拿來用就行了,我不需要操心實例創建的細節。
由此可以總結出簡單工廠的一些特點:
優點:簡單工廠根據外界給定的信息選擇創建哪個具體類的對象,明確區分了各自的職責和權力,有利於整個軟件體系結構的優化。
上面只是320 和520 兩個類型的,如果我們需要增加更多的類型的話,我們需要增加不同的Engine類型來實現IBmwEngine接口,然後在BmwEngineFactory工廠類中添加分支輸出新類型,顯然我們需要修改之前已經存在的BmwEngineFactory類,違反了軟件設計的封閉原則,當然這裏我們舉例比較簡單,修改起來也不費事,當然如果我們確實在開發中也是這樣的情況,那麼我們這樣做也沒有什麼問題,以最簡單的方式解決問題效率會更高。但是如果遇到交付的代碼不允許修改,那麼我們就需要考慮新的架構了。
缺點:
每增加一個新的類別都會在工廠類中的進行添加,也違背了軟件設計的封閉原則;
工廠類集中了所有實例創建的邏輯,違反了高內聚的責任分配原則。
三、工廠方法模式
針對簡單工廠的缺點,進一步對架構升級,引出工廠方法模式
3.1 工廠方法包括4個角色
1、抽象產品: Product
2、具體產品:ConcreteProduct
3、抽象工廠:Factory
4、具體工廠:ConcreateFactory
3.2 工廠方法實例結構圖
3.3 工廠方法實例代碼
public interface BmwEngineFactory {
public final static int BMW_320 = 320;
public final static int BMW_520 = 520;
IBmwEngine createEngine();
}
public class Bmw320EngineFactory implements BmwEngineFactory{
@Override
public Bmw320Engine createEngine() {
return new Bmw320Engine();
}
}
public class Bmw520EngineFactory implements BmwEngineFactory{
@Override
public Bmw520Engine createEngine() {
return new Bmw520Engine();
}
}
public interface IBmwEngine {
void fire();
void run();
void stop();
}
public class Bmw320Engine implements IBmwEngine {
@Override
public void fire() {
System.out.println("BMW320, fire!over!");
}
@Override
public void run() {
System.out.println("BMW320, run!over!");
}
@Override
public void stop() {
System.out.println("BMW320, stop!over!");
}
}
public class Bmw520Engine implements IBmwEngine {
@Override
public void fire() {
System.out.println("BMW520, fire!over!");
}
@Override
public void run() {
System.out.println("BMW520, run!over!");
}
@Override
public void stop() {
System.out.println("BMW520, stop!over!");
}
}
public class BmwMaker {
public static void main(String[] args) {
BmwMaker maker = new BmwMaker();
IBmwEngine engine = maker.prepareEngine320();
engine.fire();
engine.run();
engine.stop();
}
private IBmwEngine prepareEngine320() {
Bmw320EngineFactory bmwEngineFactory = new Bmw320EngineFactory();
return bmwEngineFactory.createEngine();
}
}
3.4 工廠方法實例代碼分析
上面的實例代碼包括:
抽象工廠類:BmwEngineFactory
實例工廠類:Bmw320EngineFactory、Bmw520EngineFactory,它們兩個實現了抽象工廠BmwEngineFactory
抽象產品類:IBmwEngine
具體產品類:Bmw320Engine、Bmw520Engine,它們兩個實現了抽產品IBmwEngine
測試類:BmwMaker
看起來我們的代碼結構複雜了,似乎我們並不需要工廠,這是從代碼量的角度來考慮問題,過於狹隘。換個角度,通過不同的工廠管控對應的不同類型的實例化過程,細節完全對外屏蔽,只是提供實例對象獲取接口,從這個層面上讓使用和創建分開,便於分層,便於對象創建的邏輯管理。將工廠抽象成接口,提升層級,具體的工廠分別實現,有助於擴展,並且完全符合軟件設計的開放封閉原則。
3.5 工廠方法總結
工廠方法雖然在一定程度上對簡單工廠的短板進行了彌補,但是由於具體工廠和抽象工廠的分層,讓代碼量也成倍增長了。上面只是單維度的發動機製造,如果我們進一步加入,車架(Frame)、輪胎(Tire)等種類的對象,繼續使用工廠方法來設計架構,我們將遇到比較麻煩的問題,比如爲了確保320系列的Engine、Frame和Tire的組合的正確性你需要在使用到的地方維護彼此的邏輯,不能讓520系列的零件和320的組合,那麼我們在增加730系列呢?整個邏輯的管控將會變的無比龐大和複雜,而實際上我們只想簡單的使用,需要製造320系列的車型的時候,我希望有一個工廠將整套零件一起返回,我不需要管理複雜的搭配。
如下如,增加Frame後,繼續使用工廠方法模式的架構如下,在BmwMaker類中需要添加維護320系列和520系列組件的邏輯,以確保不會被混搭。
四、抽象工廠
在組成角色中抽象工廠和工廠方法並沒有什麼不同,不同的只是兩個架構的設計,在系統的複雜度增加,產品的維度增加的時候,爲了流程的清晰和邏輯的維護簡單,需要從產品維度上調整,比如,我們不再使用產品種類這個維度來劃分工廠,而是以一個系列來劃分,比如320系列的產品,統一通過Bmw320Factory來輸出,其中包含createEngine、createFrame等方法,統一返回同一型號的組件,這樣避免了組裝車間混淆不同型號的組件。
4.1 抽象工廠包括4個角色
1、抽象產品: Product
2、具體產品:ConcreteProduct
3、抽象工廠:Factory
4、具體工廠:ConcreateFactory
4.2 抽象工廠實例結構圖
4.2 抽象工廠實例代碼
代碼機構如下如,對照看:
public interface IBmwEngine {
void fire();
void run();
void stop();
}
public class Bmw320Engine implements IBmwEngine {
@Override
public void fire() {
System.out.println("BMW320, fire!over!");
}
@Override
public void run() {
System.out.println("BMW320, run!over!");
}
@Override
public void stop() {
System.out.println("BMW320, stop!over!");
}
}
public class Bmw520Engine implements IBmwEngine {
@Override
public void fire() {
System.out.println("BMW520, fire!over!");
}
@Override
public void run() {
System.out.println("BMW520, run!over!");
}
@Override
public void stop() {
System.out.println("BMW520, stop!over!");
}
}
public interface IBmwFrame {
void install();
}
public class Bmw320Frame implements IBmwFrame {
@Override
public void install() {
System.out.println("BMW320 Frame, install!over!");
}
}
public class Bmw520Frame implements IBmwFrame {
@Override
public void install() {
System.out.println("BMW520 Frame, install!over!");
}
}
public interface BmwFactory {
IBmwEngine createEngine();
IBmwFrame createFrame();
}
public class Bmw320Factory implements BmwFactory {
@Override
public IBmwEngine createEngine() {
return new Bmw320Engine();
}
@Override
public IBmwFrame createFrame() {
return new Bmw320Frame();
}
}
public class Bmw520Factory implements BmwFactory {
@Override
public IBmwEngine createEngine() {
return new Bmw520Engine();
}
@Override
public IBmwFrame createFrame() {
return new Bmw520Frame();
}
}
public class BmwMaker {
public static void main(String[] args) {
BmwMaker maker = new BmwMaker();
maker.prepareParts320();
}
private void prepareParts320() {
Bmw320Factory bmw320Factory = new Bmw320Factory();
IBmwEngine engine = bmw320Factory.createEngine();
engine.fire();
engine.run();
engine.stop();
IBmwFrame frame = bmw320Factory.createFrame();
frame.install();
}
}
4.4 抽象工廠實例代碼分析
上面的邏輯分層相對於工廠方法模式進行了改變,可以用下面的圖來區別,工廠方法以縱向劃分成不同零件的工廠,抽象工廠以橫向車型系列進行劃分一次性返回同一型號的各種零件,從而避免了系列之間的邏輯控制的混亂。
圖4-1:工廠方法的產品的劃分,以產品種類劃分,建立工廠
圖4-2:抽象工廠的產品的劃分,以產品系列劃分,建立工廠