參考:Head First設(shè)計模式
概述
簡單工廠模式實現(xiàn)了生成產(chǎn)品類的代碼與客戶端代碼分離,在工廠類中可以添加生成產(chǎn)品的邏輯代碼。
但是簡單工廠模式不符合“開放-封閉”原則。例如要加一個 新產(chǎn)品類,就要修改 工廠類 生成產(chǎn)品的邏輯代碼,增加
if-else判斷。對于這個問題,工廠方法模式可以解決。
定義
工廠方法模式 定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法模式 讓類把實例化推遲到子類。
類圖

- 角色
- 抽象產(chǎn)品類 : Product
- 具體產(chǎn)品類 : ConcreteProductA 和 ConcreteProductB
- 抽象工廠類 : AbstractFactory
- 具體工廠類 : ConcreteFactoryA 和 ConcreteFactoryB
實例
還是以披薩店的披薩訂單為例,用工廠方法模式來處理披薩店的訂單。并且披薩店還開了加盟店,有紐約披薩店和芝加哥披薩店。
類圖
- 創(chuàng)建者類(抽象工廠類 + 具體工廠實現(xiàn)類)

- 產(chǎn)品類(抽象產(chǎn)品類 + 具體產(chǎn)品實現(xiàn)類)

代碼實現(xiàn)
- 抽象工廠類
PizzaStore
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = null;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
// 抽象的工廠方法
abstract Pizza createPizza(String type);
}
- 具體工廠實現(xiàn)類1
NYPizzaStore
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class NYStylePizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals("cheese")) {
pizza = new NYStyleCheesePizza();
} else if(type.equals("prpperoni")) {
pizza = new NYStylePepperoniPizza();
} else if(type.equals("clam")) {
pizza = new NYStyleClamPizza();
} else if(type.equals("veggie")) {
pizza = new NYStyleVeggiePizza();
}
return pizza;
}
}
- 具體工廠實現(xiàn)類2
ChicagoPizzaStore
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class ChicagoStylePizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals("cheese")) {
pizza = new ChicagoStyleCheesePizza();
} else if(type.equals("prpperoni")) {
pizza = new ChicagoStylePepperoniPizza();
} else if(type.equals("clam")) {
pizza = new ChicagoStyleClamPizza();
} else if(type.equals("veggie")) {
pizza = new ChicagoStyleVeggiePizza();
}
return pizza;
}
}
- 抽象產(chǎn)品類
Pizza
package cn.edu.nwpu.factoryMethod;
import java.util.ArrayList;
/**
*
* @author yylin
*
*/
public abstract class Pizza {
/*
* 抽象類提供了默認(rèn)基本做法, 準(zhǔn)備工作以特定順序進(jìn)行
*/
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
public void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" " + toppings.get(i));
}
}
public void bake() {
System.out.println("Bake for 25 minutes at 350");
}
public void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
public void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
}
- 具體產(chǎn)品實現(xiàn)類1
NYStyleCheesePizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class NYStyleCheesePizza extends Pizza {
/*
* 具體產(chǎn)品實現(xiàn)類中可以加入自己的特色,或者覆蓋Pizza類中的方法
*/
public NYStyleCheesePizza(){
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
- 具體產(chǎn)品實現(xiàn)類2
NYStylePepperoniPizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class NYStylePepperoniPizza extends Pizza {
}
- 具體產(chǎn)品實現(xiàn)類3
NYStyleClamPizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class NYStyleClamPizza extends Pizza {
}
- 具體產(chǎn)品實現(xiàn)類4
NYStyleVeggiePizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class NYStyleVeggiePizza extends Pizza {
}
- 具體產(chǎn)品實現(xiàn)類5
ChicagoStyleCheesePizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class ChicagoStyleCheesePizza extends Pizza {
/*
* 具體產(chǎn)品實現(xiàn)類中可以加入自己的特色,或者覆蓋Pizza類中的方法
*/
public ChicagoStyleCheesePizza() {
name = "";
dough = "";
sauce = "";
toppings.add("");
}
@Override
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
- 具體產(chǎn)品實現(xiàn)類6
ChicagoStylePepperoniPizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class ChicagoStylePepperoniPizza extends Pizza {
}
- 具體產(chǎn)品實現(xiàn)類7
ChicagoStyleClamPizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class ChicagoStyleClamPizza extends Pizza {
}
- 具體產(chǎn)品實現(xiàn)類8
ChicagoStyleVeggiePizza
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class ChicagoStyleVeggiePizza extends Pizza {
}
- 測試類
PizzaTestDrive
顧客Ethan想要紐約風(fēng)格的奶酪披薩,顧客Joel想要芝加哥風(fēng)格的奶酪披薩。
package cn.edu.nwpu.factoryMethod;
/**
*
* @author yylin
*
*/
public class PizzaTestDrive {
public static void main(String[] args) {
// 建立兩個不同的披薩店
PizzaStore nyStore = new NYStylePizzaStore();
PizzaStore chicagoStore = new ChicagoStylePizzaStore();
// 顧客Ethan的訂單
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
// 顧客Joel的訂單
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}
- 測試結(jié)果
Preparing NY Style Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
Grated Reggiano Cheese
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Sauce and Cheese Pizza
Preparing Chicago Style Deep Dish Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
Shredded Mozzarella Cheese
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Deep Dish Cheese Pizza
小結(jié)
工廠方法模式又稱為工廠模式,也叫虛擬構(gòu)造器(Virtual Constructor)模式或者多態(tài)工廠模式(Polymorphic Factory)。
在工廠方法模式中,父類負(fù)責(zé)定義創(chuàng)建對象的公共接口,而子類則負(fù)責(zé)生成具體的對象;
這樣做的目的是將類的實例化操作延遲到子類中完成;
即由子類來決定究竟應(yīng)該實例化(創(chuàng)建)哪一個類。工廠方法模式包含四個角色:
(1)抽象產(chǎn)品是定義產(chǎn)品的接口,是工廠方法模式所創(chuàng)建對象的超類型,即產(chǎn)品對象的共同父類或接口;
(2)具體產(chǎn)品實現(xiàn)了抽象產(chǎn)品接口,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建,它們之間往往一一對應(yīng);
(3)抽象工廠中聲明了工廠方法,用于返回一個產(chǎn)品,它是工廠方法模式的核心,任何在模式中創(chuàng)建對象的工廠類都必須實現(xiàn)該接口;
(4)具體工廠是抽象工廠類的子類,實現(xiàn)了抽象工廠中定義的工廠方法,并可由客戶調(diào)用,返回一個具體產(chǎn)品類的實例。工廠方法模式是簡單工廠模式的進(jìn)一步抽象和推廣。
由于使用了面向?qū)ο蟮亩鄳B(tài)性,工廠方法模式保持了簡單工廠模式的優(yōu)點,而且克服了它的缺點。
在工廠方法模式中,核心的工廠類不再負(fù)責(zé)所有產(chǎn)品的創(chuàng)建,而是將具體創(chuàng)建工作交給子類去做。
這個核心類僅僅負(fù)責(zé)給出具體工廠必須實現(xiàn)的接口,而不負(fù)責(zé)產(chǎn)品類被實例化這種細(xì)節(jié),這使得工廠方法模式可以允許系統(tǒng)在不修改工廠角色的情況下引進(jìn)新產(chǎn)品。工廠方法模式:
(1)主要優(yōu)點:增加新的產(chǎn)品類時無須修改現(xiàn)有系統(tǒng),并封裝了產(chǎn)品對象的創(chuàng)建細(xì)節(jié),系統(tǒng)具有良好的靈活性和可擴(kuò)展性;
(2)缺點在于增加新產(chǎn)品的同時需要增加新的工廠,導(dǎo)致系統(tǒng)類的個數(shù)成對增加,在一定程度上增加了系統(tǒng)的復(fù)雜性。工廠方法模式適用情況包括:
(1)一個類不知道它所需要的對象的類;
(2)一個類通過其子類來指定創(chuàng)建哪個對象;
(3)將創(chuàng)建對象的任務(wù)委托給多個工廠子類中的某一個,客戶端在使用時可以無須關(guān)心是哪一個工廠子類創(chuàng)建產(chǎn)品子類,需要時再動態(tài)指定。