你覺得工廠模式很簡單,多是由於你懂的只是冰山的一角

GitHub 3.2k Star 的Java工程師成神之路 ,不來了解一下嗎?java

GitHub 3.2k Star 的Java工程師成神之路 ,真的不來了解一下嗎?git

GitHub 3.2k Star 的Java工程師成神之路 ,真的肯定不來了解一下嗎?github

不少人認爲工廠模式很簡單,只是有一個建造工廠,幫咱們進行對象構造而已。那麼請嘗試回答下如下問題:算法

一、工廠模式分爲幾類?
二、GOF 23種設計模式中,工廠方法模式和抽象工廠模式有什麼區別?
三、不在GOF 23種設計模式中的簡單工廠模式是什麼?
四、簡單工廠模式、工廠方法模式和抽象工廠模式各自解決什麼問題?有什麼不一樣?數據庫

若是以上四個問題,你均可以很好的回答的話,那麼這篇文章就沒有繼續讀下去的必要了,不然,建議你好好學習下本文。設計模式

三種工廠模式

工廠模式能夠分爲三類:ide

  • 1)簡單工廠模式(Simple Factory)學習

  • 2)工廠方法模式(Factory Method)優化

  • 3)抽象工廠模式(Abstract Factory)this

這三種模式從上到下逐步抽象,而且更具通常性。

GOF在《設計模式》一書中將工廠模式分爲兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory)。

將簡單工廠模式(Simple Factory)看爲工廠方法模式的一種特例,二者歸爲一類。

這三種工廠模式在設計模式的分類中都屬於建立型模式

建立型模式(Creational Pattern)對類的實例化過程進行了抽象,可以將軟件模塊中對象的建立和對象的使用分離。爲了使軟件的結構更加清晰,外界對於這些對象只須要知道它們共同的接口,而不清楚其具體的實現細節,使整個系統的設計更加符合單一職責原則。

建立型模式在建立什麼(What),由誰建立(Who),什麼時候建立(When)等方面都爲軟件設計者提供了儘量大的靈活性。

建立型模式隱藏了類的實例的建立細節,經過隱藏對象如何被建立和組合在一塊兒達到使整個系統獨立的目的。

工廠模式是建立型模式中比較重要的。工廠模式的主要功能就是幫助咱們實例化對象的。之因此名字中包含工廠模式四個字,是由於對象的實例化過程是經過工廠實現的,是用工廠代替new操做的。

這樣作的好處是封裝了對象的實例化細節,尤爲是對於實例化較複雜或者對象的生命週期應該集中管理的狀況。會給你係統帶來更大的可擴展性和儘可能少的修改量。

接下來咱們分別介紹下這三種工廠模式。

簡單工廠模式

簡單工廠模式是屬於建立型模式,又叫作靜態工廠方法(Static Factory Method)模式。簡單工廠模式是由一個工廠對象決定建立出哪種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,能夠理解爲是不一樣工廠模式的一個特殊實現。

在介紹簡單工廠模式以前,咱們嘗試解決如下問題:

如今咱們要使用面向對象的形式定義計算器,爲了實現各算法之間的解耦。主要的用到的類以下:

// 計算類的基類
public abstract class Operation {

    private double value1 = 0;
    private double value2 = 0;

    public double getValue1() {
        return value1;
    }
    public void setValue1(double value1) {
        this.value1 = value1;
    }
    public double getValue2() {
        return value2;
    }
    public void setValue2(double value2) {
        this.value2 = value2;
    }
    protected abstract double getResule();
}

//加法
public class OperationAdd extends Operation {
    @Override
    protected double getResule() {
        return getValue1() + getValue2();
    }
}
//減法
public class OperationSub extends Operation {
    @Override
    protected double getResule() {
        return getValue1() - getValue2();
    }
}
//乘法
public class OperationMul extends Operation {
    @Override
    protected double getResule() {
        return getValue1() * getValue2();
    }
}
//除法
public class OperationDiv extends Operation {
    @Override
    protected double getResule() {
        if (getValue2() != 0) {
            return getValue1() / getValue2();
        }
        throw new IllegalArgumentException("除數不能爲零");
    }
}

當我想要執行加法運算時,可使用以下代碼:

public class Main {
    public static void main(String[] args) {
        OperationAdd operationAdd = new OperationAdd();
        operationAdd.setValue1(10);
        operationAdd.setValue2(5);
System.out.println(operationAdd.getResule());
    }
}

當我須要執行減法運算時,我就要建立一個OperationSub類。也就是說,我想要使用不一樣的運算的時候就要建立不一樣的類,而且要明確知道該類的名字。

那麼這種重複的建立類的工做其實能夠放到一個統一的工廠類中。簡單工廠模式有如下優勢:

一、一個調用者想建立一個對象,只要知道其名稱就能夠了。

二、屏蔽產品的具體實現,調用者只關心產品的接口。

簡單工廠模式實現方式

簡單工廠模式其實和他的名字同樣,很簡單。先來看看它的組成:

Factory:這是本模式的核心,含有必定的商業邏輯和判斷邏輯。在java中它每每由 一個具體類實現。(OperationFactory)

Product:它通常是具體產品繼承的父類或者實現的接口。在java中由接口或者抽象類來實現。(Operation)

ConcreteProduct:工廠類所建立的對象就是此角色的實例。在java中由一個具體類實現。 來用類圖來清晰的表示下的它們之間的關係(OperationAdd\OperationSub等)

在原有類的基礎上,定義工廠類:

//工廠類
public class OperationFactory {

    public static Operation createOperation(String operation) {
        Operation oper = null;
        switch (operation) {
            case "+":
                oper = new OperationAdd();
                break;
            case "-":
                oper = new OperationSub();
                break;
            case "*":
                oper = new OperationMul();
                break;

            case "/":
                oper = new OperationDiv();
                break;
            default:
                throw new UnsupportedOperationException("不支持該操做");
        }
        return oper;
    }
}

有了工廠類以後,可使用工廠建立對象:

Operation operationAdd = OperationFactory.createOperation("+");
operationAdd.setValue1(10);
operationAdd.setValue2(5);
System.out.println(operationAdd.getResule());

經過簡單工廠模式,該計算器的使用者不須要關係實現加法邏輯的那個類的具體名字,他只要知道該類對應的參數"+"就能夠了。

簡單工廠模式存在的問題

當咱們須要增長一種計算時,例如開平方。這個時候咱們須要先定義一個類繼承Operation類,其中實現平方的代碼。除此以外咱們還要修改OperationFactory類的代碼,增長一個case。這顯然是違背開閉原則的。可想而知對於新產品的加入,工廠類是很被動的。

咱們舉的例子是最簡單的狀況。而在實際應用中,極可能產品是一個多層次的樹狀結構。 簡單工廠可能就不太適用了。

簡單工廠模式總結

工廠類是整個簡單工廠模式的關鍵。包含了必要的邏輯判斷,根據外界給定的信息,決定究竟應該建立哪一個具體類的對象。經過使用工廠類,外界能夠從直接建立具體產品對象的尷尬局面擺脫出來,僅僅須要負責「消費」對象就能夠了。而沒必要管這些對象究竟如何建立及如何組織的。明確了各自的職責和權利,有利於整個軟件體系結構的優化。

可是因爲工廠類集中了全部實例的建立邏輯,違反了高內聚責任分配原則,將所有建立邏輯集中到了一個工廠類中;它所能建立的類只能是事先考慮到的,若是須要添加新的類,則就須要改變工廠類了。

當系統中的具體產品類不斷增多時候,可能會出現要求工廠類根據不一樣條件建立不一樣實例的需求.這種對條件的判斷和對具體產品類型的判斷交錯在一塊兒,很難避免模塊功能的蔓延,對系統的維護和擴展很是不利;

這些缺點在工廠方法模式中獲得了必定的解決。

工廠方法模式

工廠方法模式(Factory Method Pattern)又稱爲工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,它屬於類建立型模式。

工廠方法模式是一種實現了「工廠」概念的面向對象設計模式。就像其餘建立型模式同樣,它也是處理在不指定對象具體類型的狀況下建立對象的問題。

工廠方法模式的實質是「定義一個建立對象的接口,但讓實現這個接口的類來決定實例化哪一個類。工廠方法讓類的實例化推遲到子類中進行。」

工廠方法模式用途

工廠方法模式和簡單工廠模式雖然都是經過工廠來建立對象,他們之間最大的不一樣是——工廠方法模式在設計上徹底徹底符合「開閉原則」。

在如下狀況下可使用工廠方法模式:

一個類不知道它所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;客戶端須要知道建立具體產品的工廠類。

一個類經過其子類來指定建立哪一個對象:在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。

將建立對象的任務委託給多個工廠子類中的某一個,客戶端在使用時能夠無須關心是哪個工廠子類建立產品子類,須要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。

工廠方法模式實現方式

工廠方法模式包含以下角色:

Product:抽象產品(Operation

ConcreteProduct:具體產品(OperationAdd)

Factory:抽象工廠(IFactory)

ConcreteFactory:具體工廠(AddFactory)

這裏還用計算器的例子。在保持OperationOperationAddOperationDivOperationSubOperationMul等幾個方法不變的狀況下,修改簡單工廠模式中的工廠類(OperationFactory)。替代原有的那個"萬能"的大工廠類,這裏使用工廠方法來代替:

//工廠接口
public interface IFactory {
    Operation CreateOption();
}

//加法類工廠
public class AddFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationAdd();
    }
}

//除法類工廠
public class DivFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationDiv();
    }
}

//除法類工廠
public class MulFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationMul();
    }
}

//減法類工廠
public class SubFactory implements IFactory {
    public Operation CreateOption() {
        return new OperationSub();
    }
}

這樣,在客戶端中想要執行加法運算時,須要如下方式:

public class Main {

    public static void main(String[] args) {
        IFactory factory = new AddFactory();
        Operation operationAdd =  factory.CreateOption();
        operationAdd.setValue1(10);
        operationAdd.setValue2(5);
        System.out.println(operationAdd.getResult());
    }
}

到這裏,一個工廠方法模式就已經寫好了。

從代碼量上看,這種工廠方法模式比簡單工廠方法模式更加複雜。針對不一樣的操做(Operation)類都有對應的工廠。不少人會有如下疑問:

貌似工廠方法模式比簡單工廠模式要複雜的多?

工廠方法模式和我本身建立對象沒什麼區別?爲何要多搞出一些工廠來?

下面就針對以上兩個問題來深刻理解一下工廠方法模式。

爲何要使用工廠來建立對象?

封裝對象的建立過程

在工廠方法模式中,工廠方法用來建立客戶所須要的產品,同時還向客戶隱藏了哪一種具體產品類將被實例化這一細節,用戶只須要關心所需產品對應的工廠,無須關心建立細節,甚至無須知道具體產品類的類名。

基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它可以使工廠能夠自主肯定建立何種產品對象,而如何建立這個對象的細節則徹底封裝在具體工廠內部。工廠方法模式之因此又被稱爲多態工廠模式,是由於全部的具體工廠類都具備同一抽象父類。

爲何每種對象要單獨有一個工廠?

符合『開放-封閉原則』

主要目的是爲了解耦。在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其餘的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就能夠了。這樣,系統的可擴展性也就變得很是好,徹底符合「開閉原則。

以上就是工廠方法模式的優勢。可是,工廠模式也有一些不盡如人意的地方:

在添加新產品時,須要編寫新的具體產品類,並且還要提供與之對應的具體工廠類,系統中類的個數將成對增長,在必定程度上增長了系統的複雜度,有更多的類須要編譯和運行,會給系統帶來一些額外的開銷。

因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度,且在實現時可能須要用到DOM、反射等技術,增長了系統的實現難度。

工廠方法模式總結

工廠方法模式是簡單工廠模式的進一步抽象和推廣。

因爲使用了面向對象的多態性,工廠方法模式保持了簡單工廠模式的優勢,並且克服了它的缺點。

在工廠方法模式中,核心的工廠類再也不負責全部產品的建立,而是將具體建立工做交給子類去作。這個核心類僅僅負責給出具體工廠必須實現的接口,而不負責產品類被實例化這種細節,這使得工廠方法模式能夠容許系統在不修改工廠角色的狀況下引進新產品。

工廠方法模式的主要優勢是增長新的產品類時無須修改現有系統,並封裝了產品對象的建立細節,系統具備良好的靈活性和可擴展性;其缺點在於增長新產品的同時須要增長新的工廠,致使系統類的個數成對增長,在必定程度上增長了系統的複雜性。

抽象工廠模式

抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或相互依賴對象的接口,而無須指定它們具體的類。抽象工廠模式又稱爲Kit模式,屬於對象建立型模式。

抽象工廠模式提供了一種方式,能夠將同一產品族的單獨的工廠封裝起來。在正常使用中,客戶端程序須要建立抽象工廠的具體實現,而後使用抽象工廠做爲接口來建立這一主題的具體對象。客戶端程序不須要知道(或關心)它從這些內部的工廠方法中得到對象的具體類型,由於客戶端程序僅使用這些對象的通用接口。抽象工廠模式將一組對象的實現細節與他們的通常使用分離開來。

產品族

來認識下什麼是產品族: 位於不一樣產品等級結構中,功能相關的產品組成的家族。以下面的例子,就有兩個產品族:跑車族和商務車族。

抽象工廠模式用途

抽象工廠模式和工廠方法模式同樣,都符合開放-封閉原則。可是不一樣的是,工廠方法模式在增長一個具體產品的時候,都要增長對應的工廠。可是抽象工廠模式只有在新增一個類型的具體產品時才須要新增工廠。也就是說,工廠方法模式的一個工廠只能建立一個具體產品。而抽象工廠模式的一個工廠能夠建立屬於一類類型的多種具體產品。工廠建立產品的個數介於簡單工廠模式和工廠方法模式之間。

在如下狀況下可使用抽象工廠模式:

一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部類型的工廠模式都是重要的。

系統中有多於一個的產品族,而每次只使用其中某一產品族。

屬於同一個產品族的產品將在一塊兒使用,這一約束必須在系統的設計中體現出來。

系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於具體實現。

抽象工廠模式實現方式

抽象工廠模式包含以下角色:

AbstractFactory(抽象工廠):用於聲明生成抽象產品的方法

ConcreteFactory(具體工廠):實現了抽象工廠聲明的生成抽象產品的方法,生成一組具體產品,這些產品構成了一個產品族,每個產品都位於某個產品等級結構中;

AbstractProduct(抽象產品):爲每種產品聲明接口,在抽象產品中定義了產品的抽象業務方法;

Product(具體產品):定義具體工廠生產的具體產品對象,實現抽象產品接口中定義的業務方法。

本文的例子採用一個汽車代工廠造汽車的例子。假設咱們是一家汽車代工廠商,咱們負責給奔馳和特斯拉兩家公司製造車子。咱們簡單的把奔馳車理解爲須要加油的車,特斯拉爲須要充電的車。其中奔馳車中包含跑車和商務車兩種,特斯拉一樣也包含奔馳車和商務車。

以上場景,咱們就能夠把跑車和商務車分別對待,對於跑車有單獨的工廠建立,商務車也有單獨的工廠。這樣,之後不管是再幫任何其餘廠商造車,只要是跑車或者商務車咱們都不須要再引入工廠。一樣,若是咱們要增長一種其餘類型的車,好比越野車,咱們也不須要對跑車或者商務車的任何東西作修改。

下面是抽象產品,奔馳車和特斯拉車:

public interface BenzCar {
    //加汽油
    public void gasUp();

}

public interface TeslaCar {
    //充電
    public void charge();
}

下面是具體產品,奔馳跑車、奔馳商務車、特斯拉跑車、特斯拉商務車:

public class BenzSportCar implements BenzCar {
    public void gasUp() {
        System.out.println("給個人奔馳跑車加最好的汽油");
    }
}

public class BenzBusinessCar implements BenzCar{
    public void gasUp() {
        System.out.println("給個人奔馳商務車加通常的汽油");
    }
}

public class TeslaSportCar implements TeslaCar {
    public void charge() {
        System.out.println("給我特斯拉跑車衝滿電");
    }
}

public class TeslaBusinessCar implements TeslaCar {
    public void charge() {
        System.out.println("不用給我特斯拉商務車衝滿電");
    }
}

下面是抽象工廠:

public interface CarFactory {

    public BenzCar getBenzCar();
    public TeslaCar getTeslaCar();
}

下面是具體工廠:

public class SportCarFactory implements CarFactory {
    public BenzCar getBenzCar() {
        return new BenzSportCar();
    }

    public TeslaCar getTeslaCar() {
        return new TeslaSportCar();
    }
}

public class BusinessCarFactory implements CarFactory {
    public BenzCar getBenzCar() {
        return new BenzBusinessCar();
    }

    public TeslaCar getTeslaCar() {
        return new TeslaBusinessCar();
    }
}

「開閉原則」的傾斜性

「開閉原則」要求系統對擴展開放,對修改封閉,經過擴展達到加強其功能的目的。對於涉及到多個產品族與多個產品等級結構的系統,其功能加強包括兩方面:

增長產品族:對於增長新的產品族,工廠方法模式很好的支持了「開閉原則」,對於新增長的產品族,只須要對應增長一個新的具體工廠便可,對已有代碼無須作任何修改。

增長新的產品等級結構:對於增長新的產品等級結構,須要修改全部的工廠角色,包括抽象工廠類,在全部的工廠類中都須要增長生產新產品的方法,不能很好地支持「開閉原則」。

抽象工廠模式的這種性質稱爲「開閉原則」的傾斜性,抽象工廠模式以一種傾斜的方式支持增長新的產品,它爲新產品族的增長提供方便,但不能爲新的產品等級結構的增長提供這樣的方便。

抽象工廠模式總結

抽象工廠模式提供一個建立一系列相關或相互依賴對象的接口,而無須指定它們具體的類。抽象工廠模式又稱爲Kit模式,屬於對象建立型模式。

抽象工廠模式是全部形式的工廠模式中最爲抽象和最具通常性的一種形態。

抽象工廠模式的主要優勢是隔離了具體類的生成,使得客戶並不須要知道什麼被建立,並且每次能夠經過具體工廠類建立一個產品族中的多個對象,增長或者替換產品族比較方便,增長新的具體工廠和產品族很方便;主要缺點在於增長新的產品等級結構很複雜,須要修改抽象工廠和全部的具體工廠類,對「開閉原則」的支持呈現傾斜性。

三種工廠模式對比

簡單工廠模式的優缺點

  • 優勢:
    • 一、屏蔽產品的具體實現,調用者只關心產品的接口。
    • 二、實現簡單
  • 缺點:
    • 一、增長產品,須要修改工廠類,不符合開放-封閉原則
    • 二、工廠類集中了全部實例的建立邏輯,違反了高內聚責任分配原則

工廠方法模式的優缺點

  • 優勢:
    • 一、繼承了簡單工廠模式的優勢
    • 二、符合開放-封閉原則
  • 缺點:
    • 一、增長產品,須要增長新的工廠類,致使系統類的個數成對增長,在必定程度上增長了系統的複雜性。

抽象工廠模式的優缺點

  • 優勢:
    • 一、隔離了具體類的生成,使得客戶並不須要知道什麼被建立
    • 二、每次能夠經過具體工廠類建立一個產品族中的多個對象,增長或者替換產品族比較方便,增長新的具體工廠和產品族很方便;
  • 缺點
    • 增長新的產品等級結構很複雜,須要修改抽象工廠和全部的具體工廠類,對「開閉原則」的支持呈現傾斜性。

簡單工廠 : 用來生產同一等級結構中的任意產品。(對於增長新的產品,主要是新增產品,就要修改工廠類。符合單一職責原則。不符合開放-封閉原則)

工廠方法 :用來生產同一等級結構中的固定產品。(支持增長任意產品,新增產品時不須要更改已有的工廠,須要增長該產品對應的工廠。符合單一職責原則、符合開放-封閉原則。可是引入了複雜性)

抽象工廠 :用來生產不一樣產品族的所有產品。(增長新產品時,須要修改工廠,增長產品族時,須要增長工廠。符合單一職責原則,部分符合開放-封閉原則,下降了複雜性)

最後,三種工廠模式各有優缺點,沒有最好的,只有最合適的!

相關文章
相關標籤/搜索