溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java設(shè)計模式之工廠方法和抽象工廠怎么用

發(fā)布時間:2022-09-26 09:52:14 來源:億速云 閱讀:127 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“Java設(shè)計模式之工廠方法和抽象工廠怎么用”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Java設(shè)計模式之工廠方法和抽象工廠怎么用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

一、引出問題

如果有一個客戶老王,需要購買產(chǎn)品,產(chǎn)品分別是A、B、C。

如果用傳統(tǒng)方法實現(xiàn),分別定義A、B、C三個類,再分別創(chuàng)建他們所屬的方法。

在客戶對象中再分別調(diào)用他們的方法。

Product ClientProduct(String orderType) {
    Product product;

    if (orderType.equals("A")) {
        product = new ProductA();
    } else if (orderType.equals("B")) {
        product = new ProductB();
    } else if (orderType.equals("B")) {
        product = new ProductC();
    }
    
    // product制作過程
    product.common();
    
    return product;
}

如果我們需要再增加一個產(chǎn)品D,就需要判斷再增加一個分支,然后在分支里面創(chuàng)建產(chǎn)品對象,調(diào)用產(chǎn)品D的方法。

這樣代碼的維護性是極差的,查看我們的軟件設(shè)計七大原則,很明顯,這違反了開閉原則、依賴倒置原則.

如果又有個客戶小王,那么小王也必須依賴每個產(chǎn)品類,這樣就顯得冗雜。

二、簡單工廠(靜態(tài)工廠)

簡單工廠(靜態(tài)工廠)模式就應(yīng)用而生了。

如果我們將產(chǎn)品A、B、C抽象出來一個父類,再專門創(chuàng)建一個工廠類,在客戶購買產(chǎn)品時,只需要傳入產(chǎn)品的類型,由工廠去創(chuàng)建產(chǎn)品。

簡單工廠模式中包含如下角色:

Factory:工廠角色

工廠角色負(fù)責(zé)實現(xiàn)創(chuàng)建所有實例的內(nèi)部邏輯。

Product:抽象產(chǎn)品角色

抽象產(chǎn)品角色是所創(chuàng)建的所有對象的父類,負(fù)責(zé)描述所有實例所共有的公共接口。

ConcreteProduct:具體產(chǎn)品角色

具體產(chǎn)品角色是創(chuàng)建目標(biāo),所有創(chuàng)建的對象都充當(dāng)這個角色的某個具體類的實例。

看看我們對原始實現(xiàn)方式后的代碼。

產(chǎn)品抽象父類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Product {

    public void common(){
        System.out.println("這是產(chǎn)品父類公共方法...");
    }


}

產(chǎn)品A:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ProductA extends Product{

    public void common(){
        System.out.println("這是產(chǎn)品A方法...");
    }

}

產(chǎn)品B:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ProductB extends Product{

    public void common(){
        System.out.println("這是產(chǎn)品B方法...");
    }
}

工廠類:

/**
 * @author tcy
 * @Date 28-07-2022
 */

public class SimpleFactory {

    public Product createProduct(String orderType) {
        Product product = null;

        if (orderType.equals("A")) {
            product = new ProductA();
        } else if (orderType.equals("B")) {
            product = new ProductB();
        } else if (orderType.equals("C")) {
            product = new ProductC();
        }
        return product;
    }
}

客戶老王類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {

    SimpleFactory simpleFactory;

    public Client(SimpleFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
    }

    public Product orderProduct(String orderType) {

        Product product;    

        product = simpleFactory.createProduct(orderType);

       //調(diào)用每個產(chǎn)出相應(yīng)的方法
        product.common();
        System.out.println(product.getClass());
        return product;
    }

    public static void main(String[] args) {
        Client client=new Client(new SimpleFactory());
        client.orderProduct("A");
    }

}

這樣簡單工廠模式就實現(xiàn)了,這樣的話老王和具體的產(chǎn)品就很好的解耦了,也不需要老王再依賴具體產(chǎn)品類,依賴倒置問題就很好的解決了。

如果增加一個產(chǎn)品D,需要再重新定義一個D類,實現(xiàn)product接口,而后在工廠類中增加一個分支結(jié)構(gòu)。

顯而易見這樣實現(xiàn),缺陷依然存在:

1、工廠類集中了所有產(chǎn)品創(chuàng)建邏輯,職責(zé)過重,一旦發(fā)生異常,整個系統(tǒng)將受影響。
2、使用簡單工廠模式將會增加系統(tǒng)中類的個數(shù),在一定程序上增加了系統(tǒng)的復(fù)雜度和理解難度。
3、系統(tǒng)擴展困難,一旦增加新產(chǎn)品不得不修改工廠邏輯,在產(chǎn)品類型較多時,可能造成邏輯過于復(fù)雜。
4、簡單工廠模式由于使用了靜態(tài)工廠方法,造成工廠角色無法形成基于繼承的等級結(jié)構(gòu)。

這種方法只是一種編碼方式,并不輸入設(shè)計模式的一種,且局限于產(chǎn)品種類較少。

三、工廠方法

在簡單工廠中老王需要具體的產(chǎn)品,就在他自己的類中去創(chuàng)建需要的產(chǎn)品,老王雖然不依賴具體產(chǎn)品,但老王現(xiàn)在需要依賴工廠實現(xiàn)類了。

簡單工廠是將產(chǎn)品類抽象化,具體的產(chǎn)品由工廠類去實現(xiàn)。

如果我們將工廠類也抽象化,那就引出了我們今天第一個設(shè)計模式——工廠方法。

工廠方法有四個角色:

1、抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,調(diào)用者通過它訪問具體工廠的工廠方法 createProduct() 來創(chuàng)建產(chǎn)品。
2、具體工廠(ConcreteFactory):主要是實現(xiàn)抽象工廠中的抽象方法,完成具體產(chǎn)品的創(chuàng)建。
3、抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能。
4、具體產(chǎn)品(ConcreteProduct):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它同具體工廠之間一一對應(yīng)。

我們對簡單工廠代碼進行改造。

抽象產(chǎn)品父類、產(chǎn)品A類、產(chǎn)品B類保持不變。重點看工廠類

抽象工廠類:

/**
 * @author tcy
 * @Date 28-07-2022
 */

public abstract class AbstractFactory {

    public abstract Product createProduct(String orderType);
}

具體實現(xiàn)工廠A類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreteFactoryA extends AbstractFactory{
    @Override
    public Product createProduct(String orderType) {
        System.out.println("參數(shù)為:"+orderType);
        return new ProductA();
    }
}

具體實現(xiàn)工廠B類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreteFactoryB extends AbstractFactory{
    @Override
    public Product createProduct(String orderType) {
        return new ProductB();
    }
}

老王類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {

    AbstractFactory simpleFactory;

    public Client(AbstractFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
    }

    public Product orderProduct(String orderType) {

        Product product;

        product = simpleFactory.createProduct(orderType);

       //調(diào)用每個產(chǎn)出相應(yīng)的方法
        product.common();
        System.out.println(product.getClass());
        return product;
    }

    public static void main(String[] args) {
        Client client=new Client(new ConcreteFactoryA());
        client.orderProduct("A");
    }

}

這樣的好處就在于老王只管他要關(guān)注的抽象工廠,具體是哪個工廠實現(xiàn)類生產(chǎn)產(chǎn)品,老王也不需要關(guān)注。

典型的解耦框架。高層模塊只需要知道產(chǎn)品的抽象類,無須關(guān)心其他實現(xiàn)類,滿足迪米特法則、依賴倒置原則和里氏替換原則。

缺點也是顯而易見的:

  • 類的個數(shù)容易過多,增加復(fù)雜度。

  • 考慮到系統(tǒng)的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統(tǒng)的抽象性和理解難度。

  • 抽象產(chǎn)品只能生產(chǎn)一種產(chǎn)品。

如果對工廠方法依然一知半解的話,接著往下看工廠方法的一個典型實現(xiàn)

在JDK中對工廠方法有大量的運用,其中比較典型的是

new ArrayList<>().iterator();

我們知道集合的一個大分支依賴的是Collection接口,我們以ArrayList作為舉例。

Collection接口相當(dāng)于產(chǎn)品的抽象父類,ArrayList相當(dāng)于具體產(chǎn)品。

Iterator是一個抽象工廠,在ArrayList中有一個Itr內(nèi)部類實現(xiàn)了Iterator接口

當(dāng)我們調(diào)用集合的iterator()方法遍歷對象時,就會調(diào)用各自類的具體實現(xiàn)方法。

四、抽象工廠

有一天,產(chǎn)品A、B、C升級改造了,三種產(chǎn)品分別有紅色和藍(lán)色,如果還用工廠方法的話,那簡直是個災(zāi)難,具體工廠實現(xiàn)類需要六個。

就引出我們今天的第二個設(shè)計模式&mdash;&mdash;抽象工廠。

抽象工廠模式(Abstract Factory Pattern):提供一個接口,用于創(chuàng)建創(chuàng)建一系列相關(guān)或相互依賴對象的家族,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬于對象創(chuàng)建型模式。

抽象工廠模式與工廠方法模式區(qū)別在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu)。

而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)(各種顏色),一個工廠等級結(jié)構(gòu)可以負(fù)責(zé)多個不同產(chǎn)品等級結(jié)構(gòu)(不同顏色)中的產(chǎn)品對象的創(chuàng)建 。

抽象工廠依然是四個角色:

  • AbstractFactory:抽象工廠

  • ConcreteFactory:具體工廠

  • AbstractProduct:抽象產(chǎn)品

  • Product:具體產(chǎn)品

    我們開始改造工廠方法代碼,既然是要把產(chǎn)品都分成一組,那理應(yīng)把產(chǎn)品A、B、C都抽象出來,再讓工廠類去實現(xiàn)各個產(chǎn)品的不同顏色,也就是概念中的&mdash;&mdash;用于創(chuàng)建創(chuàng)建一系列相關(guān)或相互依賴對象的家族。

接口看改造后的代碼:

產(chǎn)品抽象類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public interface Product {

    public void common();

}

產(chǎn)品抽象A家族類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class ProductA implements Product {

    public abstract void common();

}

產(chǎn)品抽象B家族類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class ProductB implements Product {

    public abstract void common();
}

具體紅色產(chǎn)品A類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class RedProductA extends ProductA{
    @Override
    public void common() {
        System.out.println("這是紅色的產(chǎn)品A");
    }
}

具體藍(lán)色產(chǎn)品A類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class BlueProductA extends ProductA {

    @Override
    public void common() {
        System.out.println("這是藍(lán)色的產(chǎn)品A");
    }
}

抽象A家族工廠類:

/**
 * @author tcy
 * @Date 28-07-2022
 */

public interface AbstractProductFactory {

    public ProductA createProduct(String orderType);
}

實現(xiàn)A家族工廠類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreateProductAFactory implements AbstractProductFactory{

    @Override
    public ProductA createProduct(String orderType) {
        return new BlueProductA();
    }
}

老王類:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {

    ConcreateProductAFactory simpleFactory;

    public Client(ConcreateProductAFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
    }

    public ProductA orderProduct(String orderType) {

        ProductA product;

        product = simpleFactory.createProduct(orderType);

       //調(diào)用每個產(chǎn)出相應(yīng)的方法
        product.common();
        System.out.println(product.getClass());
        return product;
    }

    public static void main(String[] args) {
        Client client=new Client(new ConcreateProductAFactory());
        client.orderProduct("A");
    }

}

這樣的話,每天工廠類可以把A的產(chǎn)品家族類(紅、藍(lán))都實現(xiàn),抽象工廠模式隔離了具體類的生成,使得老王并不需要知道什么產(chǎn)品被創(chuàng)建,從具體的產(chǎn)品解耦出來。

  • 當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能夠保證客戶端始終只使用同一個產(chǎn)品族中的對象。

如果要增加新產(chǎn)品、和新工廠很容易,如果再增加一個等級(顏色)代碼修改起來就很痛苦了。

抽象工廠模式在Spring中有大量的運用。

比較典型的是,BeanFactory 是用于管理 Bean 的一個工廠,所有工廠都是 BeanFactory 的子類。這樣我們可以通過 IOC 容器來管理訪問 Bean,根據(jù)不同的策略調(diào)用 getBean() 方法,從而獲得具體對象。

BeanFactory 的子類主要有

ClassPathXmlApplicationContext、

XmlWebApplicationContext、

StaticWebApplicationContext、

StaticApplicationContext。

在 Spring 中,DefaultListableBeanFactory 實現(xiàn)了所有工廠的公共邏輯。

讀到這里,這篇“Java設(shè)計模式之工廠方法和抽象工廠怎么用”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI