Java設計模式1:抽象工廠模式(Abstract Factory)

意圖

提供一個創建一系列相關或相互依賴對象的接口,而無需制定他們具體的類

適用性

一下情況可以使用Abstract Factory模式

一個系統要獨立於它的產品的創建、組合和表示時

一個系統要由多個產品系列中的一個來配置時

當你要強調一系列相關的產品對象的設計以便進行聯合使用時

當你提供一個產品類庫,而指向顯示他們的接口而不是實現時`

結構

這裏寫圖片描述

AbstractProductA 和 AbstractProductB是兩個抽象的產品,之所以爲抽象,是因爲他們都有可能有兩種或多種不同的實現,ProductA1、ProductA2和ProductB1、ProductB2 就是對兩個抽象產品的具體分類的實現。

AbstractFactory 則是一個抽象的工廠接口,它裏面應該包含所有的產品創建的抽象方法。而ConcreteFactory 1 和 ConcreteFactory 2 就是具體的工廠了。

我們通常是在運行時再創建一個 ConcreteFactory 類的實例對象,這個具體的工廠再創建具有特定實現的產品對象,也就是說,爲創建不同的產品對象,客戶端應該使用不同的具體工廠。

AbstractFactory模式的優缺點

1、分離了具體的類,解耦

2、易於交換產品系列

3、有利於產品的一致性

4、難以支持新品種的產品

實現

假設你現在是客戶,要買一輛車。

public class Client {

    public static void main(String[] args){
        BenzS600 benzCar = new BenzS600();
        benzCar.drive();
    }
}

問題在哪裏呢,就是我們在代碼裏面把對象BenzS600直接new出來了,如果我們需求改變,當然這裏不明顯,你可以理解爲,原來我們使用MySql作爲數據庫,但是現在我們要使用Oracle,那麼我們所有的寫死的代碼全要改,這就是耦合度太高引起的“牽一髮而動全身”,現在呢,我們可以使用抽象工廠模式,我們可以通過抽象工廠去獲取對應產品的工廠(FerrariFactory),然後具體的工廠去給我們提車,而我們需求變了之後,只需要找到對應的工廠,告訴他們我們要買什麼車就行了。

我們現在來設計一下

超級工廠類

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:15
 */
public class FactoryProducer {
    public static AbstractFactory getFactory(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class cl = Class.forName(type);
        System.out.println("創建工廠" + type);
        return (AbstractFactory) cl.newInstance();
    }
}

抽象工廠類

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:15
 */
public abstract class AbstractFactory {
    public abstract Car getCar(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}

工廠類

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:15
 */
public class BenzFactory extends AbstractFactory {
    @Override
    public Car getCar(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class cl = Class.forName(type);
        return (BenzCar) cl.newInstance();
    }
}
package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:15
 */
public class FerrariFactory extends AbstractFactory {

    @Override
    public Car getCar(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class cl = Class.forName(type);
        return (FerrariCar) cl.newInstance();
    }
}

汽車類

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:05
 * 最高級的抽象產品
 */
public interface Car {
    abstract void drive();
}

法拉利4S

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:07
 * 抽象產品
 */
public abstract class FerrariCar implements Car {
}

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:09
 * 具體的產品Ferrari430
 */
public class Ferrari430 extends FerrariCar {
    @Override
    public void drive() {
        System.out.println("Ferrari 430 come......");
    }
}

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:11
 */
public class FerrariLaFerrari extends FerrariCar {
    @Override
    public void drive() {
        System.out.println("Ferrari LaFerrari come......");
    }
}

奔馳4S

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:12
 */
public abstract class BenzCar implements Car {
}

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:13
 */
public class BenzGLS450 extends BenzCar {
    @Override
    piublic void drive() {
        System.out.println("Benz GLS450 come......");
    }
}

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:13
 */
public class BenzS600 extends BenzCar {
    @Override
    public void drive() {
        System.out.println("Benz S600 come......");
    }
}

買車了

package abstractFactory;

/**
 * @Author fitz.bai
 * @Date 2018/8/26 15:22
 */
public class Client {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        AbstractFactory abstractFactory = FactoryProducer.getFactory("abstractFactory.FerrariFactory");

        Car ferrariCar = abstractFactory.getCar("abstractFactory.Ferrari430");
        ferrariCar.drive();

        Car ferrariLaFeCar = abstractFactory.getCar("abstractFactory.FerrariLaFerrari");
        ferrariLaFeCar.drive();

        AbstractFactory abstractFactory1 = FactoryProducer.getFactory("abstractFactory.BenzFactory");

        Car benzCar = abstractFactory1.getCar("abstractFactory.BenzS600");
        benzCar.drive();

        Car benzCar1 = abstractFactory1.getCar("abstractFactory.BenzGLS450");
        benzCar1.drive();
    }
}
/**
創建工廠abstractFactory.FerrariFactory
Ferrari 430 come......
Ferrari LaFerrari come......
創建工廠abstractFactory.BenzFactory
Benz S600 come......
Benz GLS450 come......
*/

從結果看出,我們首先提供工廠名字,抽象工廠給我們找到了具體的工廠,然後我們又告訴他我們需要什麼車,他就給了我我們什麼車。
還有一個問題,假如有一天我的項目想進行一個重構,重整類路徑,包路徑,比方說生產Ferrari430的地方有100處,getCar(type)豈不是要修改100處?當然不用,我們可以寫在配置文件裏面。

實際應用

JDK中的抽象工廠模式有很多應用,典型的比如線程池。我們使用線程池的時候,可以使用ThreadPoolExecutor,根據自己的喜好傳入corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler這幾個參數,new出一個指定的ThreadPoolExecutor出來。

JDK給開發者提供了Executors這個類,可以讓用戶產生ThreadPoolExecutor和使用ThreadPoolExecutor分離開,比如可以讓Executors提供一個單線程的線程池Executors.newSingleThreadExecutor()、讓Executors提供一個無界線程池Executors.newCachedThreadPool()等,這樣,開發者可以不用關心線程池是如何去實現的,直接使用Executors方法提供給開發者的ThreadPoolExecutor就可以了。

可以對照上面的結構圖,看看線程池實現的源碼,再深入瞭解AbstractFactory Pattern。

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