工廠模式 一:簡單工廠模式 1. 問題的引出 我們打算做一個製作pizza的系統,從訂購到出貨,初始代碼如下: 客戶端通過調用pizza類的orderPizza方法來創建pizza,根據type的不同來獲取不同種類的pizza,然而以上的設計存在著很多問題: 1. Pizza類中存在大量的if el ...
工廠模式
一:簡單工廠模式
1. 問題的引出
我們打算做一個製作pizza的系統,從訂購到出貨,初始代碼如下:
public class Pizza{
Pizza orderPizza(String type){
Pizza pizza;
// 會引起代碼變化的部分
if(type.equals("cheese")){
pizza =new CheesePizza();
}else if (type.equals("greek")){
pizza=new GreekPizza();
}else if(type.equals("pepperoni")){
pizza=new pepperoniPizza();
}
//不需要改變的部分代碼 這是對pizza的一系列處理
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
客戶端通過調用pizza類的orderPizza方法來創建pizza,根據type的不同來獲取不同種類的pizza,然而以上的設計存在著很多問題:
- Pizza類中存在大量的if-else,使得整個類的代碼冗長,既不容易測試又很影響性能 ,程式運行中需要做大量的條件判斷。
- 當需要增加新的pizza的時候,必須修改Pizza類的源代碼,違反了開閉原則。
- 客戶端只能通過new關鍵字來創建對象,使得Pizza類和客戶端耦合度很高,違反了迪米特法則。
因此我們引出了簡單工廠模式
,此模式能在一定程度上解決這個問題
。
2. 簡單工廠模式概述
簡單工廠模式不屬於GoF23個經典設計模式,但它是學習工廠模式的基礎,其思想:首先將需要創建的各種對象(各種風味pizza)封裝到不同對象中,這些類稱為具體產品類
,將公共部分提取到抽象產品類
,然後提供一個工廠類
用於創建各種產品,在工廠類中提供創建產品的工廠方法,根據參數獲取不同的產品對象。
其定義如下:
簡單工廠模式(Simple Factory Pattern):定義一個工廠類,它可以根據參數的不同返回不同類的實例,被創建的實例通常都具有共同的父類。因為在簡單工廠模式中用於創建實例的方法是靜態(static)方法,因此簡單工廠模式又被稱為靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。
3. 簡單工廠模式結構圖
4. 簡單工廠模式角色
Factory(工廠角色)
:即工廠類,負責創建所有產品實例的內部邏輯,其中提供了靜態的工廠方法factoryMethod(),外界直接調用此方法來返回抽象產品類型。Product(抽象產品角色)
:工廠類所創建的所有對象的基類,也是工廠類返回類型,符合依賴倒轉原則以及開閉原則,封裝了各種產品對象的公共方法。ProductA(具體產品角色)
:由簡單工廠創建得到,每個具體產品都繼承或實現了抽象產品角色
在簡單工廠模式中
5.簡單工廠模式解決上述問題
抽象產品角色:
public interface IPizza {
void prepare();
void bake();
void cut();
void box();
}
具體產品A:
public class PizzaA implements IPizza {
@Override
public void prepare() {
}
@Override
public void bake() {
}
@Override
public void cut() {
}
@Override
public void box() {
}
}
具體產品B:
public class PizzaB implements IPizza {
@Override
public void prepare() {
}
@Override
public void bake() {
}
@Override
public void cut() {
}
@Override
public void box() {
}
}
工廠角色:
public class SimplePizzaFactory {
public static IPizza createPizza(String type){
IPizza pizza=null;
if(type.equals("A")){
pizza =new PizzaA();
}else if (type.equals("B")){
pizza=new PizzaB();
}
return pizza;
}
}
客戶端:
public class Client {
public static void main(String[] args) {
IPizza pizza = SimplePizzaFactory.createPizza("A");
// 創建pizza之後的工作
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}
6:簡單工廠模式總結
優點:
- 簡單工廠模式使得對象的創建和使用分離開來。
- 簡單工廠模式將創建對象的複雜邏輯封裝起來。
- 使用者只需要傳入參數即可獲得對應的產品。
缺點:
- 違背開閉原則,一旦假如了新的產品就必須要更改工廠創建產品的邏輯。
- 工廠類集中所有產品的創建過程,一旦類不能正常工作,將引起整個系統的故障。
二:工廠方法模式
1.問題的引出
簡單工廠模式雖然解決了產品對象的創建問題,但是仍然存在很大的設計問題:當添加新的產品時候,必須通過修改客戶端傳過去的類型參數,其次還需要修改工廠中的if-else邏輯,顯然違反了開閉原則,此外簡單工廠模式所有的產品都是同一個工廠所創,工廠類職責很重,違反了單一職責原則
,因此將引出第二種工廠模式->工廠方法模式。
2.工廠方法模式概述
不再提供一個統一的工廠類來創建所有的產品對象,而是針對不同的產品提供不同的工廠,系統提供一個與產品等級結構對應的工廠等級結構
,工廠方法模式定義如下:
工廠方法模式(Factory Method Pattern):定義一個用於創建對象的介面,讓子類決定將哪一個類實例化。工廠方法模式讓一個類的實例化延遲到其子類。工廠方法模式又簡稱為工廠模式(Factory Pattern),又可稱作虛擬構造器模式(Virtual Constructor Pattern)或多態工廠模式(Polymorphic Factory Pattern)。工廠方法模式是一種類創建型模式。
3.工廠方法模式結構圖
4.工廠方法模式角色
Product(抽象產品角色)
:用來定義產品的介面,是產品對象的基類。ProductB(具體產品)
:實現了抽象產品介面Factory(抽象工廠)
:聲明瞭工廠方法,用於返回一個產品,抽象工廠是工廠方法模式的核心,所有的工廠類都必須實現此方法。ProductAFactory(具體工廠)
:是抽象工廠子類,實現抽象工廠方法,返回具體的產品實例
5.工廠方法模式解決上述問題
結構如圖:
代碼如下:
抽象產品角色:
public interface Pizza {
// 準備
void prepare();
// 烘烤
void bake();
// 切
void cut();
// 裝盒
void box();
}
具體產品角色:
public class PizzaA implements Pizza {
@Override
public void prepare() {
System.out.println("pizzaA開始準備");
}
@Override
public void bake() {
System.out.println("pizzaA開始烘烤");
}
@Override
public void cut() {
System.out.println("pizzaA開始切");
}
@Override
public void box() {
System.out.println("pizzaA開始裝盒");
}
}
public class PizzaB implements Pizza {
@Override
public void prepare() {
System.out.println("pizzaB開始準備");
}
@Override
public void bake() {
System.out.println("pizzaB開始烘烤");
}
@Override
public void cut() {
System.out.println("pizzaB開始切");
}
@Override
public void box() {
System.out.println("pizzaB開始裝盒");
}
}
抽象工廠:
public interface PizzaFactory {
Pizza createPizza();
}
具體工廠角色:
public class PizzaAFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new PizzaA();
}
}
public class PizzaBFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new PizzaB();
}
}
客戶端:
public class Client {
public static void main(String[] args) {
// 針對抽象編程 PizzaAFactory可根據DI(依賴註入)進去
// 整個客戶端就不需要對修改變化,全部是針對抽象編程
PizzaFactory factory = new PizzaAFactory();
Pizza pizza = factory.createPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}
6.工廠方法模式總結
優點:
- 對客戶端隱藏了具體產品的創建細節,無需知道傳入什麼參數進去。
- 假如新產品時候,不需要更改客戶端以及抽象產品角色以及抽象工廠角色,只需要添加新的工廠類以及具體產品即可,完全符合開閉原則。
缺點:
- 如果產品的個數種類很多,那麼必然會出現大量的具體工廠類,增加了系統的複雜度,會給系統帶來額外的開銷。
三:抽象工廠模式
1.問題的引出
工廠方法通過引入工廠等級結構,解決簡單工廠職責過重(所有的產品都在一個工廠里產生)的問題,但是工廠方法會額外產生大量的工廠類,ProductA、ProductB、ProductC........,會給系統帶來很大的開銷,因此我們可以將相同類型的產品組成產品族,由同一個工廠生產
,即抽象工廠模式的核心。
2.抽象工廠模式概述
抽象工廠模式為創建一組對象提供瞭解決方案,與工廠方法模式相比,抽象工廠模式中的工廠負責創建一組,其定義如下:
抽象工廠模式(Abstract Factory Pattern):提供一個創建一系列相關或相互依賴對象的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,它是一種對象創建型模式。
3.抽象工廠結構圖
- AbstractFactory(抽象工廠):聲明瞭一族產品的方法,每個方法對應一種產品。
- Factory1(具體工廠):,實現了抽象工廠中的方法,生成一組具體產品,這些產品構成了產品族,某個產品都位於某個產品等級中。
- AbstractProductA:不同產品實現或繼承不同的產品介面。
- ProductA:具體產品,實現抽象產品中的方法。
4.抽象工廠模式實例
場景如下:為了保證客戶的實用安全,確保原料一致,所以需要一個工廠來生產原料,即此工廠負責原料家族中的每種原料,即工廠需要生產麵團、醬料、芝士等,但是不同區域的風味不一致,抽象工廠模式設計如下圖:
代碼如下:
AbstractFactory(抽象工廠角色):
//原料生產工廠 每個區域的原料工廠都需要實現此介面
public abstract class PizzaIngredientFactory {
//每個原料都有一個對應的方法創建該原料
// 生產麵團
abstract Dough createDough();
// 生產醬
abstract Sauce createSauce();
}
具體工廠:紐約原料加工廠
// 紐約原料工廠
public class NYPizzaIngredientFactory extends PizzaIngredientFactory {
@Override
Dough createDough() {
return new DoughA();
}
@Override
Sauce createSauce() {
return new SauceA();
}
}
具體工廠:中國原料加工廠
// 中國原料工廠
public class ChinaIngredientFactory extends PizzaIngredientFactory {
@Override
Dough createDough() {
return new DoughB();
}
@Override
Sauce createSauce() {
return new SauceB();
}
}
抽象產品角色:麵團
// 麵團
public interface Dough {
}
抽象產品角色:醬料
// 醬料
public interface Sauce {
}
具體產品角色:麵團A
public class DoughA implements Dough{
}
具體產品角色:麵團B
public class DoughB implements Dough{
}
具體產品角色:醬料A
public class SauceA implements Sauce {
}
具體產品角色:醬料B
public class SauceB implements Sauce {
}
5.抽象工廠方法總結
我們可以發現要是在增加新的產品族很方便,只需要擴展新的具體工廠,但是要擴展產品的等級結構(在抽象工廠中加入新的原料),會發現完全違背開閉原則,修改量巨大,抽象工廠的產品等級結構以工廠方法模式形式呈現,同樣的產品族也是以工廠方法模式形式呈現,而產品族依賴產品等級結構,也就是說一旦產品等級結構是穩定不變的,那麼整個抽象工廠就是很穩定的。
優點:
- 增加新的產品族很方便,完全符合對修改關閉
- 我們要替換整個產品線的話是非常容易的,只需要修改對應的具體工廠即可。
缺點:
- 增加新的產品等級結構需要修改大量的代碼,完全違背開閉原則。
四:簡單工廠VS工廠方法 && 工廠方法模式VS抽象工廠模式
先來回顧一下這三者的結構圖:
簡單工廠模式:
工廠方法模式:
抽象工廠模式:
簡單工廠模式VS工廠方法模式
- 簡單工廠模式把所有產品都放在一個工廠里生產。
- 簡單工廠違背開閉原則。
- 工廠方法模式將產品的具體實現推遲到子類中,且針對每個產品都有對應的實現。
- 工廠方法模式符合開閉原則。
工廠方法模式VS抽象工廠模式
- 抽象工廠在產品族上符合開閉原則,但是在產品等級結構上違背開閉原則。
- 抽象工廠將一系類的產品組合起來,很明顯符合組合復用原則。
- 抽象工廠可以看做是工廠方法的變形。相對於產品族來說,是工廠方法模式,相對於產品等級結構來說,也是工廠方法模式。