一起學設計模式 - 工廠模式

工廠模式是JAVA中最常用的設計模式之一,使用工廠模式後,創建對象的時候不在將創建邏輯暴露給客戶端,而是通過實現接口的方式創建對象,這種設計模式也是對象實例化的最佳方式。

概述

工廠模式的三種形態

  • 簡單工廠(Simple Factory)
  • 工廠方法(Factory Method)
  • 抽象工廠(Abstract Factory)

簡單工廠

簡單工廠模式屬於工廠模式的小弟,未被收納進GOF 23中,但是也被頻繁使用

簡單工廠模式

1.創建一個Animal接口

interface Shape {
    void draw();
}

2.創建DogPig實現Animal接口

class Circle implements Shape {
    public Circle() {
        System.out.println("創建圓形模型");
    }

    @Override
    public void draw() {
        System.out.println("畫了一個圓形");
    }
}

class Square implements Shape {
    public Square() {
        System.out.println("創建了方形模型");
    }

    @Override
    public void draw() {
        System.out.println("畫了一個方形");
    }
}

3.創建工廠類SimpleFactory,定義一個基於參數信息實例化具體對象的方法

public class SimpleFactory {

    private final static String CIRCLE = "CIRCLE";
    private final static String SQUARE = "SQUARE";

    public static Shape getFactory(String type) {
        switch (type) {
            case CIRCLE:
                return new Circle();
            case SQUARE:
                return new Square();
            default:
                throw new NullPointerException("未描繪任何圖形");
        }
    }

    public static void main(String[] args) {
        Shape circle = SimpleFactory.getFactory(CIRCLE);
        circle.draw();

        Shape square = SimpleFactory.getFactory(SQUARE);
        square.draw();
    }
}

4.日誌

創建圓形模型
畫了一個圓形
創建了方形模型
畫了一個方形

分析: 從上述代碼中可以發現,簡單工廠擁有一定判斷能力,構建結果取決於入參,使用起來也十分的方便,也正因爲使用太過方便而導致高耦合的情況,所有對象實例化都需要依賴它,一旦出問題,影響的會是整個系統

使用場景: 創建簡單,無複雜業務邏輯的對象

工廠方法

前面說到過簡單工廠模式存在耦合,且違反了開閉原則,那麼這一問題在工廠方法模式中可以很容易的解決掉,它可以做到添加新的產品而不破壞已有代碼

工廠方法模式

工廠方法模式:定義一個創建對象的接口,由它的實現類來決定具體實現,其模式又被稱爲工廠模式(Factory Pattern)

1.新增ImageReaderFactory抽象工廠接口,用來構建具體的對象

interface ImageReader {
    void read();
}
interface ImageReaderFactory {
    ImageReader create();
}

2.相比單一實例化的簡單工廠模式而言,方法工廠模式更加的靈活,針對不同的產品(圖片讀取器)提供不同的工廠。

class JpgReader implements ImageReader {
    public JpgReader() {
        System.out.println("創建Jpg讀取器");
    }

    @Override
    public void read() {
        System.out.println("讀取Jpg文件");
    }
}

class PngReader implements ImageReader {
    public PngReader() {
        System.out.println("創建Png讀取器");
    }

    @Override
    public void read() {
        System.out.println("讀取Png文件");
    }
}
class JpgFactory implements ImageReaderFactory {
    @Override
    public ImageReader create() {
        System.out.println("實例化Jpg文件工廠");
        return new JpgReader();
    }
}

class PngFactory implements ImageReaderFactory {
    @Override
    public ImageReader create() {
        System.out.println("實例化Png文件工廠");
        return new PngReader();
    }
}

3.創建測試類,當然實際使用過程中,實現工廠方法除了可以實例化具體對象,還可以初始化某些資源配置,比如連接池、創建文件等

public class MethodFactory {
    public static void main(String[] args) {
        ImageReaderFactory png = new PngFactory();
        ImageReader pngReader = png.create();
        pngReader.read();

        ImageReaderFactory jpg = new JpgFactory();
        ImageReader jpgReader = jpg.create();
        jpgReader.read();
    }
}

4.日誌

實例化Png文件工廠
創建Png讀取器
讀取Png文件
實例化Jpg文件工廠
創建Jpg讀取器
讀取Jpg文件

優點:

  • 屏蔽了客戶端實例化對象的細節,用戶只需要關心自己使用的工廠即可。
  • 加入新的產品(圖片讀取器),無需更改現有代碼,提高系統擴展性,符合開閉原則
  • 具備多態性,又被稱爲多態工廠模式

缺點: 每次需要編寫新的對象和對象工廠類,隨業務發展,一定程度上增加了系統複雜度

抽象工廠

  • 抽象工廠模式是爲創建一組對象提供提供的解決方案,與工廠方法模式相比,抽象工廠模式中的具體工廠不只是創建某一種產品,而是負責一組(產品族)。
  • 抽象工廠模式(Abstract Factory Pattern):提供了創建一系列相互依賴對象的接口,無需指定具體類
  • 抽象工廠模式是圍繞着一個超級工廠工作,創造其它的工廠類,也被稱爲工廠的工廠,這種類型的設計模式是創造性的模式,因爲這種模式提供了創建對象的最佳方法之一。

起源

抽象工廠模式的起源或者最早的應用,是用於創建分屬於不同操作系統的視窗構建。比如:命令按鍵(Button)與文字框(Text)都是視窗構建,在UNIX操作系統的視窗環境和Windows操作系統的視窗環境中,這兩個構建有不同的本地實現,它們的細節有所不同。

在每一個操作系統中,都有一個視窗構建組成的構建家族。在這裏就是Button和Text組成的產品族。而每一個視窗構件都構成自己的等級結構,由一個抽象角色給出抽象的功能描述,而由具體子類給出不同操作系統下的具體實現。

444

可以發現在上面的產品類圖中,有兩個產品的等級結構,分別是Button等級結構和Text等級結構。同時有兩個產品族,也就是UNIX產品族和Windows產品族。UNIX產品族由UNIX Button和UNIX Text產品構成;而Windows產品族由Windows Button和Windows Text產品構成。

555

系統對產品對象的創建需求由一個工程的等級結構滿足,其中有兩個具體工程角色,即UnixFactory和WindowsFactory。UnixFactory對象負責創建Unix產品族中的產品,而WindowsFactory對象負責創建Windows產品族中的產品。這就是抽象工廠模式的應用,抽象工廠模式的解決方案如下圖:

666

顯然,一個系統只能夠在某一個操作系統的視窗環境下運行,而不能同時在不同的操作系統上運行。所以,系統實際上只能消費屬於同一個產品族的產品。

在現代的應用中,抽象工廠模式的使用範圍已經大大擴大了,不再要求系統只能消費某一個產品族了。因此,可以不必理會前面所提到的原始用意。

摘抄自《JAVA與模式》之抽象工廠模式:http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html

需求: 開發一款《王者榮耀》,支持多操作系統和多控制方式操作控制界面控制,並提供相應的工廠類來封裝這些類的初始化過程

抽象工廠模式

1.創建不同的操作系統接口

interface Linux {
    void controller();
}

interface Windows {
    void controller();
}

2.基於不同操作系統實現控制邏輯

class LinuxController implements Linux {
    @Override
    public void controller() {
        System.out.println("Linux 控制 《王者榮耀》");
    }
}

class WindowsController implements Windows {
    @Override
    public void controller() {
        System.out.println("Windows 控制 《王者榮耀》");
    }
}

3.創建一個工廠類,基於接口分別實現操作控制界面控制兩種方式的工廠

interface AbstractFactory {
    Linux installLinux();

    Windows installWindows();
}

class OperationFactory implements AbstractFactory {

    @Override
    public Linux installLinux() {
        System.out.println("安裝Linux操作控制系統");
        return new LinuxController();
    }

    @Override
    public Windows installWindows() {
        System.out.println("安裝Windows操作控制系統");
        return new WindowsController();
    }
}

class InterfaceFactory implements AbstractFactory {
    @Override
    public Linux installLinux() {
        System.out.println("安裝Linux界面控制系統");
        return new LinuxController();
    }

    @Override
    public Windows installWindows() {
        System.out.println("安裝Windows界面控制系統");
        return new WindowsController();
    }
}

4.創建《王者榮耀》進行測試

public class KingGlory {

    public static void main(String[] args) {

        AbstractFactory operationFactory = new OperationFactory();
        operationFactory.installLinux().controller();
        operationFactory.installWindows().controller();
        System.out.println("========================================================");
        AbstractFactory interfaceFactory = new InterfaceFactory();
        interfaceFactory.installLinux().controller();
        interfaceFactory.installWindows().controller();

    }
}

5.日誌

安裝Linux操作控制系統
Linux 控制 《王者榮耀》
安裝Windows操作控制系統
Windows 控制 《王者榮耀》
========================================================
安裝Linux界面控制系統
Linux 控制 《王者榮耀》
安裝Windows界面控制系統
Windows 控制 《王者榮耀》

分析

使用抽象工廠模式來定義的一系列對象通常是相關或相互依賴的,這些產品對象就構成了一個產品族,也就是抽象工廠定義了一個產品族。這就帶來非常大的靈活性,切換產品族的時候,只要提供不同的抽象工廠實現就可以了,也就是說現在是以一個產品族作爲一個整體被切換,從上文中可以發現,如果我們需要切換控制方式,只需要變更下對應的工廠類即可

優點:

  • 分離接口和實現:客戶端使用抽象工廠來創建需要的對象,而客戶端根本就不知道具體的實現是誰,客戶端只是面向產品的接口編程而已。也就是說,客戶端從具體的產品實現中解耦。
  • 切換產品族變得容易:對於增加新的產品族,抽象工廠模式很好地支持了開閉原則,只需要增加具體產品並對應增加一個新的具體工廠,對已有代碼無須做任何修改(如:新增一種手柄操作支持)。

缺點:

  • 不易擴展新產品:如果需要給整個產品族添加一個新的產品,那麼就需要修改抽象工廠,這樣就會導致修改所有的工廠實現類(如:新增一種操作系統的支持,那麼Factory代碼需要全部修改)。

使用場景:

  • 一個系統不應當依賴於產品類實例如何被創建、組合和表達的細節,這對於所有形態的工廠模式都是重要的。
  • 這個系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
  • 同屬於同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。
  • 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於實現。

- 說點什麼

全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter1/battcn-factory

  • 個人QQ:1837307557
  • battcn開源羣(適合新手):391619659

微信公衆號:battcn(歡迎調戲)

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