前言
前一篇介紹了《設計模式—簡單工廠模式詳解》,可以知道簡單工廠模式有一些弊端:
- 工廠類集中了所有實例(產品)的創建邏輯,一旦這個工廠不能正常工作,整個系統都會受到影響;
- 違背“開放 - 關閉原則”,一旦添加新產品就不得不修改工廠類的邏輯,這樣就會造成工廠邏輯過於複雜;
- 簡單工廠模式由於使用了靜態工廠方法,靜態方法不能被繼承和重寫,會造成工廠角色無法形成基於繼承的等級結構。
爲了解決上述的問題,我們又使用了一種新的設計模式:工廠方法模式。
概述
定義
工廠方法模式,又稱工廠模式、多態工廠模式和虛擬構造器模式,通過定義工廠父類負責定義創建對象的公共接口,而子類則負責生成具體的對象。
主要作用
將類的實例化(具體產品的創建)延遲到工廠類的子類(具體工廠)中完成,即由子類來決定應該實例化(創建)哪一個類。
解決的問題
工廠一旦需要生產新產品就需要修改工廠類的方法邏輯,違背了“開放 - 關閉原則。
之所以可以解決簡單工廠的問題,是因爲工廠方法模式把具體產品的創建推遲到工廠類的子類(具體工廠)中,此時工廠類不再負責所有產品的創建,而只是給出具體工廠必須實現的接口,這樣工廠方法模式在添加新產品的時候就不修改工廠類邏輯而是添加新的工廠子類,符合開放封閉原則,克服了簡單工廠模式中缺點。
模式詳細設計思路
如上圖UML圖所示,工廠方法模式主要包含如下角色:
- 抽象工廠(Factory)角色:是工廠方法模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現這個接口。
- 具體工廠(Concrete Factory)角色:這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,並且受到應用程序調用以創建產品對象。在上圖中有兩個這樣的角色:FactoryA與FactoryB。
- 抽象產品(Product)角色:工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
- 具體產品(Concrete Product)角色:這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創建,它們之間往往一一對應。
使用步驟
- 創建抽象工廠類,定義具體工廠的公共接口;
- 創建抽象產品類 ,定義具體產品的公共接口;
- 創建具體產品類(繼承抽象產品類) & 定義生產的具體產品;
- 創建具體工廠類(繼承抽象工廠類),定義創建對應具體產品實例的方法;
- 外界通過調用具體工廠類的方法,從而創建不同具體產品類的實例。
案例(demo)
案例介紹
背景:王老闆有一間塑料加工廠(僅生產A類產品);隨着客戶需求的變化,客戶需要生產B類產品;以後可能還會有更多的產品線出現。
痛點:改變原有塑料加工廠的配置和變化非常困難,假設下一次客戶需要再發生變化,再次改變將增大非常大的成本;
解決方案:小成決定置辦塑料分廠B來生產B類產品,即選擇工廠方法模式。
案例實現
創建抽象產品類,如下所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description: 抽象產品類
* @Author: garrettwang
* @Date: 2019/12/4 21:16
* @Modified By:
*/
public abstract class Product {
/**
* 產品方法
*/
public abstract void show();
}
創建產品具體的類,如下圖所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/4 21:17
* @Modified By:
*/
public class ProductA extends Product {
@Override
public void show() {
System.out.println("生產出了產品A");
}
}
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/4 21:18
* @Modified By:
*/
public class ProductB extends Product {
@Override
public void show() {
System.out.println("生產出了產品B");
}
}
創建抽象工廠類,如下所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/5 18:42
* @Modified By:
*/
public abstract class Factory {
public abstract Product createProduct();
}
創建具體工廠類,兩個具體工廠類,如下圖所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/5 18:43
* @Modified By:
*/
public class FactoryA extends Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/5 18:43
* @Modified By:
*/
public class FactoryB extends Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
測試代碼類,如下所示:
package com.linezonedata.dp.factoryMethod;
/**
* @Description:
* @Author: garrettwang
* @Date: 2019/12/4 21:23
* @Modified By:
*/
public class Test {
public static void main(String[] args){
new FactoryA().createProduct().show();
new FactoryB().createProduct().show();
}
}
測試結果如下:
生產出了產品A
生產出了產品B