工廠模式:像點外賣一樣創建對象
一、生活比喻:你每天都在用“工廠模式”
想象一下點外賣的場景:
graph TD
A[顧客] -->|“我要一份披薩”| B(外賣平臺)
B --> C{判斷需求}
C -->|海鮮披薩| D[海鮮披薩店]
C -->|水果披薩| E[水果披薩店]
D --> F[制作海鮮披薩]
E --> G[制作水果披薩]
F --> H[送達顧客]
G --> H
關鍵點:
- 你不需要知道披薩具體怎么做
- 你只需要告訴平臺“要什么類型”
- 平臺自動分配對應的店鋪制作
這恰恰就是工廠模式的核心思想:
將對象的創建和使用分離,使用者無需關心對象的具體創建細節
二、工廠模式三大類型(圖文對比)
類型1:簡單工廠模式(外賣平臺基礎版)
結構圖:`
客戶
↓
[披薩工廠]
/ \
海鮮披薩 水果披薩`
代碼示例:`java
// 1. 定義披薩接口
interface Pizza {
void prepare();
void bake();
}
// 2. 具體披薩實現
class SeafoodPizza implements Pizza {
public void prepare() {
System.out.println("準備海鮮材料");
}
public void bake() {
System.out.println("烤制海鮮披薩");
}
}
class FruitPizza implements Pizza {
public void prepare() {
System.out.println("準備水果材料");
}
public void bake() {
System.out.println("烤制水果披薩");
}
}
// 3. 簡單工廠
class PizzaFactory {
public static Pizza createPizza(String type) {
if ("seafood".equals(type)) {
return new SeafoodPizza();
} else if ("fruit".equals(type)) {
return new FruitPizza();
}
return null;
}
}
// 4. 客戶使用
public class Customer {
public static void main(String[] args) {
// 就像點外賣,只需要說“要海鮮披薩”
Pizza pizza = PizzaFactory.createPizza("seafood");
pizza.prepare();
pizza.bake();
}
}`
優點:簡單直接,適合類型不多的情況
缺點:新增披薩類型需要修改工廠類,違反開閉原則
類型2:工廠方法模式(品牌專賣店)
結構圖:`
[披薩店接口]
↑
_
| |
海鮮披薩店 水果披薩店
| |
海鮮披薩 水果披薩`
代碼示例:`java
// 1. 抽象工廠接口
interface PizzaStore {
Pizza createPizza(); // 工廠方法
}
// 2. 具體工廠
class SeafoodPizzaStore implements PizzaStore {
public Pizza createPizza() {
return new SeafoodPizza(); // 專做海鮮披薩
}
}
class FruitPizzaStore implements PizzaStore {
public Pizza createPizza() {
return new FruitPizza(); // 專做水果披薩
}
}
// 3. 客戶使用
public class Customer {
public static void main(String[] args) {
// 選擇海鮮披薩店
PizzaStore store = new SeafoodPizzaStore();
Pizza pizza = store.createPizza(); // 自動得到海鮮披薩
pizza.prepare();
pizza.bake();
}
}`
優點:
- 符合開閉原則,新增產品只需新增工廠
- 每個工廠職責單一
適用場景:
- 不同品牌有自己專屬的產品線
- 需要創建的對象類型會不斷擴展
類型3:抽象工廠模式(連鎖餐飲集團)
現實比喻:
- 麥當勞:生產漢堡 + 薯條 + 可樂(一套美式快餐)
- 肯德基:生產漢堡 + 蛋撻 + 奶茶(一套中式快餐)
結構圖:`
[快餐工廠接口]
/ \
漢堡接口 飲品接口
↑ ↑
麥當勞工廠 肯德基工廠
| |
麥當勞漢堡 肯德基漢堡
麥當勞可樂 肯德基奶茶`
代碼示例:`java
// 1. 抽象產品族
interface Hamburger {
void eat();
}
interface Drink {
void drink();
}
// 2. 具體產品
class McDonaldHamburger implements Hamburger {
public void eat() {
System.out.println("吃麥當勞漢堡");
}
}
class KFCHamburger implements Hamburger {
public void eat() {
System.out.println("吃肯德基漢堡");
}
}
class CocaCola implements Drink {
public void drink() {
System.out.println("喝可口可樂");
}
}
class MilkTea implements Drink {
public void drink() {
System.out.println("喝奶茶");
}
}
// 3. 抽象工廠(生產一套產品)
interface FastFoodFactory {
Hamburger createHamburger();
Drink createDrink();
}
// 4. 具體工廠
class McDonaldFactory implements FastFoodFactory {
public Hamburger createHamburger() {
return new McDonaldHamburger();
}
public Drink createDrink() {
return new CocaCola(); // 固定搭配可樂
}
}
class KCFactory implements FastFoodFactory {
public Hamburger createHamburger() {
return new KFCHamburger();
}
public Drink createDrink() {
return new MilkTea(); // 固定搭配奶茶
}
}
// 5. 客戶使用
public class Customer {
public static void main(String[] args) {
// 選擇麥當勞套餐
FastFoodFactory factory = new McDonaldFactory();
Hamburger burger = factory.createHamburger();
Drink drink = factory.createDrink();
burger.eat(); // 輸出:吃麥當勞漢堡
drink.drink(); // 輸出:喝可口可樂
}
}`
核心特點:
- 創建的是產品族(一組相關產品)
- 保證產品之間的兼容性(麥當勞不會配奶茶)
適用場景:
- 系統需要一系列相關的產品
- 需要確保產品之間的兼容性
- 產品族需要整體替換
三、快速選擇指南(決策樹)
開始選擇工廠模式
↓
需要創建單個對象嗎?
├── 是 → 對象類型固定且少嗎?
│ ├── 是 → 使用簡單工廠
│ └── 否 → 使用工廠方法
│
└── 否 → 需要創建一組相關對象嗎?
├── 是 → 使用抽象工廠
└── 否 → 重新分析需求
四、真實應用場景
Spring框架中的工廠模式
// Spring的BeanFactory就是工廠模式的典型應用
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
// 你不用new UserService(),由Spring工廠創建和管理
JDK中的工廠模式
Calendar.getInstance():根據時區創建日歷對象NumberFormat.getInstance():創建數字格式化對象
五、核心思想
- 封裝變化:將對象創建的變化封裝在工廠中
- 解耦:使用者與具體產品類解耦
- 單一職責:工廠只負責創建,產品只負責功能
- 開閉原則:對擴展開放,對修改關閉
記住這個口訣:
“不要自己new,找工廠要;
要什么產品,給什么參數;
工廠怎么造,你不用管。”
工廠模式就像現實生活中的“制造商-消費者”關系,讓代碼更靈活、更易維護!