工廠模式的三種實現,就這麼簡單! 工廠模式

工廠模式

工廠模式是開發中常用的一種設計模式,每一種設計模式都會極大的解決程序設計方面的問題,工廠模式也是一樣,本文將會用通俗的語言來解釋什麼是工廠模式?工廠模式的種類、代碼示例、每種工廠模式的優缺點和工廠模式適用的場景。

爲什麼要是使用工廠模式?

首先我們用一個生動故事來描述下什麼是工廠模式,這會讓你更快的理解工廠模式,爲後面理解的工廠模式的幾種實現方式打下基礎。

假如,你需要讓公司開一個收入證明爲自己貸款買房提供收入證明,一般開收入證明的過程是:

  1. 打印收入證明;
  2. 在收入證明上蓋上公司的章;

貫穿整個過程,可以知道,你需要創建一個收入證明,並使用收入證明爲貸款買房提供資料。這個過程中,有兩個關鍵的行爲:創建收入證明,使用收入證明。創建收入證明的過程中又分爲兩步:打印、蓋章。不熟悉這個流程的同事在創建收入證明的時候,往往會遇到很多麻煩導致開收入證明頻頻受阻,於是公司決定把員工開收入證明這件事做個優化,以前需要兩步做的事,現在只需要發一份郵件給財務部門,財務部門就會在下班之前就會把蓋好章的收入證明送到工位,這就是生活中遇到的工廠模式

說了這麼多,工廠模式究竟解決了生活中的哪些問題呢?

在這個生活案例中,它讓員工創建收入證明這件事情變得更加簡單,員工不需要知道收入證明是怎麼創建的,只需要發一份郵件給財務部門,財務部門就會幫助員工打印並蓋章。而且在後續的公司發展中,如果需要在收入證明中蓋上更多的章,員工也不需要自己取熟悉整個流程,拿着收入證明跑斷腿的到各個部門去蓋章。

那麼,在程序的世界中,如何使用代碼演示員工爲貸款買房,去公司開收入證明這個行爲呢?又是如何用代碼展示工廠模式的呢?

類比上面的例子,假如有個收入證明類 創建只需要new一下就行,入參是打印證明給證明蓋章,如果後續收入證明的蓋章變了,需要修改入參。這就需要改大量調用創建收入證明類的new代碼。

於是這時工廠模式就可以使用了,工廠模式將類的創建和類的使用分離出來,當 Class A 想調用 Class B ,那麼A只是調用B的方法,而至於B的實例化,就交給工廠類。

那又有人說,也可以把這些創建過程的代碼放到類的構造函數裏,同樣可以降低重複率,而且構造函數本身的作用也是初始化對象。針對這個觀點,我們可以對比下工廠模式相較於構造函數的優點:

優點:

  1. 靜態工廠方法有名字而構造函數沒有,因爲工廠方法可以有多個,通過名字來區別各個方法,但構造函數名字只能有一個,只能通過參數來區別,所以使用靜態工廠方法更明瞭。

  2. 靜態工廠方法支持條件性實例化,就是說你創建對象時,有時需要添加一些條件判斷是否應該創建,如果滿足條件則返回一個實例,不滿足則返回NULL,比如單例模式。構造函數時做不到這樣的,構造函數的功能需要保持單一,只爲了構造而存在,而靜態工廠方法可以很簡單的做到。

  3. 方法能夠返回返回類型的子類型

這就是工廠模式在創建對象上的一些優點,而工廠模式最核心的知識點是:將對象的創建和使用做分離。請默唸三遍。

抓住了核心點,再去了解工廠模式的各種實現就簡單的多了,工廠模式一般可以分爲三種:

  • 簡單/靜態工廠模式
  • 工廠方法模式
  • 抽象工廠模式

我們學習步驟按照:工廠方法模式 到 簡單靜態工廠模式 到 抽象工廠模式,示例都非常簡單,一看就懂,文中的代碼我放在github上感興趣的同學可以下載:

github地址: java23種設計模式代碼示例--工廠模式

我知道大家都是愛心人士,白嫖當然不是你們的習慣,歡迎大家來一波素質三連:關注、點贊、點star

工廠方法模式

工廠方法相對比較和簡單\靜態工廠相對簡單比較容易理解。

如果我們需要在工廠裏造一臺手機,那麼先定義一個phone抽象類,手機必須要有打電話功能,加一個call抽象方法

package com.shuai.design.factory.normals;

public abstract class Phone {

    // 所有的手機必須要有打電話的功能
    public abstract void call();

}

創建一個手機的工廠接口,裏面有個createPhone方法,其他類型手機都要繼承這個接口,創建手機必須實現這個方法

package com.shuai.design.factory.normals;

import com.shuai.design.factory.simples.Phone;

public interface PhoneFactory {

    Phone createPhone();
}

創建小米手機類。繼承phone,實現call方法

package com.shuai.design.factory.normals;

import com.shuai.design.factory.simples.Phone;

public class MiPhone extends Phone {

    @Override
    public void call() {
        System.out.println("this is MI call");
    }
}

創建小米手機工廠

package com.shuai.design.factory.normals;

public class MiPhoneFactory implements PhoneFactory {

    @Override
    public MiPhone createPhone() {
        return new MiPhone();
    }
}

類似小米手機,實現華爲手機類,繼承phoen抽象類,實現call方法

package com.shuai.design.factory.normals;

import com.shuai.design.factory.simples.Phone;

public class HuaWeiPhone extends Phone {

    @Override
    public void call() {
        System.out.println("this is HuaWei Phone");
    }
}

實現華爲手機工廠

package com.shuai.design.factory.normals;

public class HuaWeiPhoneFactory implements PhoneFactory{

    @Override
    public HuaWeiPhone createPhone() {
        return new HuaWeiPhone();
    }
}

簡單靜態工廠模式

靜態工廠相對於工廠方法模式簡單的多,首先創建phone的抽象類

package com.shuai.design.factory.simples;

public abstract class Phone {

    // 所有的手機必須要有打電話的功能
    public abstract void call();

}

再創建phone的構建工廠類,根據傳入的類型創建不同類型的手機

package com.shuai.design.factory.simples;

public class PhoneFactory {

    public static MiPhone createMiPhone() {
        return new MiPhone();
    }

    public static HuaWeiPhone createHuaWeiPhone() {
        return new HuaWeiPhone();
    }

    public static Phone createPhone(String type) {
        if ("Mi".equals(type)) {
            return new MiPhone();
        } else {
            return new HuaWeiPhone();
        }
    }
}

實現小米手機類

package com.shuai.design.factory.simples;

public class MiPhone extends Phone {

    @Override
    public void call() {
        System.out.println("this is MI call");
    }
}

實現華爲手機類

package com.shuai.design.factory.simples;

public class HuaWeiPhone extends Phone {

    @Override
    public void call() {
        System.out.println("this is HuaWei Phone");
    }
}

抽象工廠模式

定義:爲創建一組相關或相互依賴的對象提供一個接口,而且無須指定它們的具體類

圖爲:

這裏還是用創建手機的方式來實現抽象工廠,先創建一個phone的抽象類,裏面不僅有call方法,還有手機的屏幕類型

package com.shuai.design.factory.abstracts;

public abstract class Phone {

    // 所有的手機必須要有打電話的功能
    public abstract void call();

    // 手機的屏幕類型
    public abstract void screenType();

}

再創建一個手機構建工廠的父接口

package com.shuai.design.factory.abstracts;

public interface PhoneFactory {

    Phone createMiPhone();

    Phone createHuaWeiPhone();

}

首先所有小米手機和華爲手機都必須實現通話功能,重寫call方法

package com.shuai.design.factory.abstracts;


public abstract class MiPhone extends Phone {

    @Override
    public void call() {
        System.out.println("this is MI call");
    }

}

package com.shuai.design.factory.abstracts;


public abstract class HuaWeiPhone extends Phone {

    @Override
    public void call() {
        System.out.println("this is HuaWei Phone");
    }

}

在根據手機的屏幕類型分爲小米摺疊屏手機:

package com.shuai.design.factory.abstracts;

public class FoldingScreenMiPhone extends MiPhone {

    @Override
    public void screenType() {
        System.out.println("this is 小米摺疊屏手機");
    }

}

在根據手機的屏幕類型分爲華爲摺疊屏手機:

package com.shuai.design.factory.abstracts;

public class FoldingScreenHuaWeiPhone extends HuaWeiPhone {

    @Override
    public void screenType() {
        System.out.println("this is 華爲摺疊屏手機");
    }

}

在根據手機的屏幕類型分爲小米曲面屏屏手機:

package com.shuai.design.factory.abstracts;

public class CurvedScreenMiPhone extends MiPhone {

    @Override
    public void screenType() {
        System.out.println("this is 小米曲面屏手機");
    }
}

在根據手機的屏幕類型分爲華爲曲面屏手機:

package com.shuai.design.factory.abstracts;

public class CurvedScreenHuaWeiPhone extends HuaWeiPhone{

    @Override
    public void screenType(){
        System.out.println("this is 華爲曲面屏手機");

    }

}

針對不同的屏幕類型手機,抽象出根據屏幕類型的構建工廠,有曲面屏手機工廠和摺疊屏手機工廠:

package com.shuai.design.factory.abstracts;
//曲面屏手機工廠
public class CurvedScreenPhoneFactory implements PhoneFactory {

    @Override
    public CurvedScreenMiPhone createMiPhone() {
        return new CurvedScreenMiPhone();
    }

    @Override
    public CurvedScreenHuaWeiPhone createHuaWeiPhone() {
        return new CurvedScreenHuaWeiPhone();
    }
}

摺疊屏手機工廠

package com.shuai.design.factory.abstracts;
//摺疊屏手機工廠
public class FoldingScreenPhoneFactory implements PhoneFactory{

    @Override
    public FoldingScreenMiPhone createMiPhone() {
        return new FoldingScreenMiPhone();
    }

    @Override
    public FoldingScreenHuaWeiPhone createHuaWeiPhone() {
        return new FoldingScreenHuaWeiPhone();
    }

}

再寫一個測試類測試一下結果:

package com.shuai.design.factory.abstracts;

public class Test {

    public static void main(String[] args) {

        // 創建一個華爲曲面屏手機
        CurvedScreenHuaWeiPhone curvedScreenHuaWeiPhone = new CurvedScreenPhoneFactory().createHuaWeiPhone();
        System.out.println("curvedScreenHuaWeiPhone 的手機類型爲:");
        curvedScreenHuaWeiPhone.screenType();

        // 創建一個小米曲面屏手機
        CurvedScreenMiPhone curvedScreenMiPhone = new CurvedScreenPhoneFactory().createMiPhone();
        System.out.println("curvedScreenMiPhone 的手機類型爲:");
        curvedScreenMiPhone.screenType();

        // 創建一個華爲摺疊屏手機
        FoldingScreenHuaWeiPhone foldingScreenHuaWeiPhone = new FoldingScreenPhoneFactory().createHuaWeiPhone();
        System.out.println("foldingScreenHuaWeiPhone 的手機類型爲:");
        foldingScreenHuaWeiPhone.screenType();

        // 創建一個小米摺疊屏手機
        FoldingScreenMiPhone foldingScreenMiPhone = new FoldingScreenPhoneFactory().createMiPhone();
        System.out.println("foldingScreenMiPhone 的手機類型爲:");
        foldingScreenMiPhone.screenType();

    }

}

抽象工廠模式的使用場景:一個對象族(或是一組沒有任何關係的對象)都有相同的約束,則可以使用抽象工廠模式。通過工廠類,只要知道工廠類是誰,我就能創建出一個需要的對象

缺點

擴展產品族困難。比如在phone中類型增加一個帶手寫筆類型的手機,那麼每個已經實現的手機類就都需要實現這個方法。這嚴重違反了開閉原則。

優點:

增加等級簡單。如果在摺疊屏手機下增加一個雙摺疊屏和三摺疊屏的手機這就比較簡單,只需要在摺疊屏手機構建工廠下面修改就行。

總結

實際上,一般開發過程中,我們使用簡單工廠模式比較多,抽象工廠模式的話需要業務比較大的情況下才會用到。如果你有更好的觀點,歡迎在評論區提出,互相學習。

參考資料:

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