工廠模式的三種實(shí)現(xiàn),就這么簡單!

工廠模式

工廠模式是開發(fā)中常用的一種設(shè)計(jì)模式,每一種設(shè)計(jì)模式都會(huì)極大的解決程序設(shè)計(jì)方面的問題,工廠模式也是一樣,本文將會(huì)用通俗的語言來解釋什么是工廠模式?工廠模式的種類、代碼示例、每種工廠模式的優(yōu)缺點(diǎn)和工廠模式適用的場景。

為什么要是使用工廠模式?

首先我們用一個(gè)生動(dòng)故事來描述下什么是工廠模式,這會(huì)讓你更快的理解工廠模式,為后面理解的工廠模式的幾種實(shí)現(xiàn)方式打下基礎(chǔ)。

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

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

貫穿整個(gè)過程,可以知道,你需要?jiǎng)?chuàng)建一個(gè)收入證明,并使用收入證明為貸款買房提供資料。這個(gè)過程中,有兩個(gè)關(guān)鍵的行為:創(chuàng)建收入證明,使用收入證明。創(chuàng)建收入證明的過程中又分為兩步:打印、蓋章。不熟悉這個(gè)流程的同事在創(chuàng)建收入證明的時(shí)候,往往會(huì)遇到很多麻煩導(dǎo)致開收入證明頻頻受阻,于是公司決定把員工開收入證明這件事做個(gè)優(yōu)化,以前需要兩步做的事,現(xiàn)在只需要發(fā)一份郵件給財(cái)務(wù)部門,財(cái)務(wù)部門就會(huì)在下班之前就會(huì)把蓋好章的收入證明送到工位,這就是生活中遇到的工廠模式。

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

在這個(gè)生活案例中,它讓員工創(chuàng)建收入證明這件事情變得更加簡單,員工不需要知道收入證明是怎么創(chuàng)建的,只需要發(fā)一份郵件給財(cái)務(wù)部門,財(cái)務(wù)部門就會(huì)幫助員工打印并蓋章。而且在后續(xù)的公司發(fā)展中,如果需要在收入證明中蓋上更多的章,員工也不需要自己取熟悉整個(gè)流程,拿著收入證明跑斷腿的到各個(gè)部門去蓋章。

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

類比上面的例子,假如有個(gè)收入證明類 創(chuàng)建只需要new一下就行,入?yún)⑹?code>打印證明和給證明蓋章,如果后續(xù)收入證明的蓋章變了,需要修改入?yún)?。這就需要改大量調(diào)用創(chuàng)建收入證明類的new代碼。

于是這時(shí)工廠模式就可以使用了,工廠模式將類的創(chuàng)建和類的使用分離出來,當(dāng) Class A 想調(diào)用 Class B ,那么A只是調(diào)用B的方法,而至于B的實(shí)例化,就交給工廠類。

那又有人說,也可以把這些創(chuàng)建過程的代碼放到類的構(gòu)造函數(shù)里,同樣可以降低重復(fù)率,而且構(gòu)造函數(shù)本身的作用也是初始化對(duì)象。針對(duì)這個(gè)觀點(diǎn),我們可以對(duì)比下工廠模式相較于構(gòu)造函數(shù)的優(yōu)點(diǎn):

優(yōu)點(diǎn):

  1. 靜態(tài)工廠方法有名字而構(gòu)造函數(shù)沒有,因?yàn)楣S方法可以有多個(gè),通過名字來區(qū)別各個(gè)方法,但構(gòu)造函數(shù)名字只能有一個(gè),只能通過參數(shù)來區(qū)別,所以使用靜態(tài)工廠方法更明了。

  2. 靜態(tài)工廠方法支持條件性實(shí)例化,就是說你創(chuàng)建對(duì)象時(shí),有時(shí)需要添加一些條件判斷是否應(yīng)該創(chuàng)建,如果滿足條件則返回一個(gè)實(shí)例,不滿足則返回NULL,比如單例模式。構(gòu)造函數(shù)時(shí)做不到這樣的,構(gòu)造函數(shù)的功能需要保持單一,只為了構(gòu)造而存在,而靜態(tài)工廠方法可以很簡單的做到。

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

這就是工廠模式在創(chuàng)建對(duì)象上的一些優(yōu)點(diǎn),而工廠模式最核心的知識(shí)點(diǎn)是:將對(duì)象的創(chuàng)建和使用做分離。請默念三遍。

抓住了核心點(diǎn),再去了解工廠模式的各種實(shí)現(xiàn)就簡單的多了,工廠模式一般可以分為三種:

  • 簡單/靜態(tài)工廠模式
  • 工廠方法模式
  • 抽象工廠模式

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

github地址: java23種設(shè)計(jì)模式代碼示例--工廠模式

我知道大家都是愛心人士,白嫖當(dāng)然不是你們的習(xí)慣,歡迎大家來一波素質(zhì)三連:關(guān)注、點(diǎn)贊、點(diǎn)star

工廠方法模式

工廠方法相對(duì)比較和簡單\靜態(tài)工廠相對(duì)簡單比較容易理解。

如果我們需要在工廠里造一臺(tái)手機(jī),那么先定義一個(gè)phone抽象類,手機(jī)必須要有打電話功能,加一個(gè)call抽象方法

package com.shuai.design.factory.normals;

public abstract class Phone {

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

}

創(chuàng)建一個(gè)手機(jī)的工廠接口,里面有個(gè)createPhone方法,其他類型手機(jī)都要繼承這個(gè)接口,創(chuàng)建手機(jī)必須實(shí)現(xiàn)這個(gè)方法

package com.shuai.design.factory.normals;

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

public interface PhoneFactory {

    Phone createPhone();
}

創(chuàng)建小米手機(jī)類。繼承phone,實(shí)現(xiàn)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");
    }
}

創(chuàng)建小米手機(jī)工廠

package com.shuai.design.factory.normals;

public class MiPhoneFactory implements PhoneFactory {

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

類似小米手機(jī),實(shí)現(xiàn)華為手機(jī)類,繼承phoen抽象類,實(shí)現(xiàn)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");
    }
}

實(shí)現(xiàn)華為手機(jī)工廠

package com.shuai.design.factory.normals;

public class HuaWeiPhoneFactory implements PhoneFactory{

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

簡單靜態(tài)工廠模式

靜態(tài)工廠相對(duì)于工廠方法模式簡單的多,首先創(chuàng)建phone的抽象類

package com.shuai.design.factory.simples;

public abstract class Phone {

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

}

再創(chuàng)建phone的構(gòu)建工廠類,根據(jù)傳入的類型創(chuàng)建不同類型的手機(jī)

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();
        }
    }
}

實(shí)現(xiàn)小米手機(jī)類

package com.shuai.design.factory.simples;

public class MiPhone extends Phone {

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

實(shí)現(xiàn)華為手機(jī)類

package com.shuai.design.factory.simples;

public class HuaWeiPhone extends Phone {

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

抽象工廠模式

定義:為創(chuàng)建一組相關(guān)或相互依賴的對(duì)象提供一個(gè)接口,而且無須指定它們的具體類

圖為:

抽象工廠

這里還是用創(chuàng)建手機(jī)的方式來實(shí)現(xiàn)抽象工廠,先創(chuàng)建一個(gè)phone的抽象類,里面不僅有call方法,還有手機(jī)的屏幕類型

package com.shuai.design.factory.abstracts;

public abstract class Phone {

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

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

}

再創(chuàng)建一個(gè)手機(jī)構(gòu)建工廠的父接口

package com.shuai.design.factory.abstracts;

public interface PhoneFactory {

    Phone createMiPhone();

    Phone createHuaWeiPhone();

}

首先所有小米手機(jī)和華為手機(jī)都必須實(shí)現(xiàn)通話功能,重寫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");
    }

}

在根據(jù)手機(jī)的屏幕類型分為小米折疊屏手機(jī):

package com.shuai.design.factory.abstracts;

public class FoldingScreenMiPhone extends MiPhone {

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

}

在根據(jù)手機(jī)的屏幕類型分為華為折疊屏手機(jī):

package com.shuai.design.factory.abstracts;

public class FoldingScreenHuaWeiPhone extends HuaWeiPhone {

    @Override
    public void screenType() {
        System.out.println("this is 華為折疊屏手機(jī)");
    }

}

在根據(jù)手機(jī)的屏幕類型分為小米曲面屏屏手機(jī):

package com.shuai.design.factory.abstracts;

public class CurvedScreenMiPhone extends MiPhone {

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

在根據(jù)手機(jī)的屏幕類型分為華為曲面屏手機(jī):

package com.shuai.design.factory.abstracts;

public class CurvedScreenHuaWeiPhone extends HuaWeiPhone{

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

    }

}

針對(duì)不同的屏幕類型手機(jī),抽象出根據(jù)屏幕類型的構(gòu)建工廠,有曲面屏手機(jī)工廠和折疊屏手機(jī)工廠:

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

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

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

折疊屏手機(jī)工廠

package com.shuai.design.factory.abstracts;
//折疊屏手機(jī)工廠
public class FoldingScreenPhoneFactory implements PhoneFactory{

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

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

}

再寫一個(gè)測試類測試一下結(jié)果:

package com.shuai.design.factory.abstracts;

public class Test {

    public static void main(String[] args) {

        // 創(chuàng)建一個(gè)華為曲面屏手機(jī)
        CurvedScreenHuaWeiPhone curvedScreenHuaWeiPhone = new CurvedScreenPhoneFactory().createHuaWeiPhone();
        System.out.println("curvedScreenHuaWeiPhone 的手機(jī)類型為:");
        curvedScreenHuaWeiPhone.screenType();

        // 創(chuàng)建一個(gè)小米曲面屏手機(jī)
        CurvedScreenMiPhone curvedScreenMiPhone = new CurvedScreenPhoneFactory().createMiPhone();
        System.out.println("curvedScreenMiPhone 的手機(jī)類型為:");
        curvedScreenMiPhone.screenType();

        // 創(chuàng)建一個(gè)華為折疊屏手機(jī)
        FoldingScreenHuaWeiPhone foldingScreenHuaWeiPhone = new FoldingScreenPhoneFactory().createHuaWeiPhone();
        System.out.println("foldingScreenHuaWeiPhone 的手機(jī)類型為:");
        foldingScreenHuaWeiPhone.screenType();

        // 創(chuàng)建一個(gè)小米折疊屏手機(jī)
        FoldingScreenMiPhone foldingScreenMiPhone = new FoldingScreenPhoneFactory().createMiPhone();
        System.out.println("foldingScreenMiPhone 的手機(jī)類型為:");
        foldingScreenMiPhone.screenType();

    }

}

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

1

缺點(diǎn)

擴(kuò)展產(chǎn)品族困難。比如在phone中類型增加一個(gè)帶手寫筆類型的手機(jī),那么每個(gè)已經(jīng)實(shí)現(xiàn)的手機(jī)類就都需要實(shí)現(xiàn)這個(gè)方法。這嚴(yán)重違反了開閉原則。

優(yōu)點(diǎn):

增加等級(jí)簡單。如果在折疊屏手機(jī)下增加一個(gè)雙折疊屏和三折疊屏的手機(jī)這就比較簡單,只需要在折疊屏手機(jī)構(gòu)建工廠下面修改就行。

總結(jié)

實(shí)際上,一般開發(fā)過程中,我們使用簡單工廠模式比較多,抽象工廠模式的話需要業(yè)務(wù)比較大的情況下才會(huì)用到。如果你有更好的觀點(diǎn),歡迎在評(píng)論區(qū)提出,互相學(xué)習(xí)。

參考資料:

歡迎關(guān)注公眾號(hào):java之旅

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容