工厂模式:像点外卖一样创建对象
一、生活比喻:你每天都在用“工厂模式”
想象一下点外卖的场景:
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,找工厂要;
要什么产品,给什么参数;
工厂怎么造,你不用管。”
工厂模式就像现实生活中的“制造商-消费者”关系,让代码更灵活、更易维护!