設計模式:工廠模式(簡單工廠/工廠方法/抽象工廠全面對比理解)

目錄

 

一、 簡單介紹

二、簡單工廠

2.1 新需求,要求根據簡單工廠設計

2.2 簡單工廠流程圖

2.3 簡單工廠實例代碼

2.4 簡單工廠總結

三、工廠方法模式

3.1 工廠方法包括4個角色

3.2 工廠方法實例結構圖

3.3 工廠方法實例代碼

3.4 工廠方法實例代碼分析

3.5 工廠方法總結

四、抽象工廠

4.1 抽象工廠包括4個角色

4.2 抽象工廠實例結構圖

4.2 抽象工廠實例代碼

4.4 抽象工廠實例代碼分析


一、 簡單介紹

實際上我們可能常用的工廠模式只是簡單工廠(靜態方法工廠),嚴格說來這可能只是一種編程優化的習慣,不能說程爲是一種設計模式,但是不管是簡單工廠工廠方法還是抽象工廠都是爲軟件架構服務的,具體選擇哪一種需要仔細考量,絕對不能爲用而用,不要裝逼裝高深,簡單、易用、易於理解和維護纔是目的。這篇文章對工廠模式進行一個大概的介紹,便於理解記憶

上圖中的工廠方法和抽象工廠都包含了相同的角色,但是在具體的架構中是有所不同的。

 

 

二、簡單工廠

簡單工廠,也叫作靜態方法工廠,包含了三個角色工廠類、抽象產品,具體產品,所有的產品都在工廠類類裏面統一初始化,並通過工廠類的靜態方法統一輸出。

通過一個需求來切入。

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

dcb4bc0db65c9af350133eb142d11cee3eb.jpg

 

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

dcb4bc0db65c9af350133eb142d11cee3eb.jpg

 

 

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:抽象工廠的產品的劃分,以產品系列劃分,建立工廠

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章