意圖
提供一個創建一系列相關或相互依賴對象的接口,而無需制定他們具體的類
適用性
一下情況可以使用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。