工厂模式
- [🍔 为什么需要工厂模式?](#🍔 为什么需要工厂模式?)
- 简单工厂模式
-
- [💡 核心思想](#💡 核心思想)
- [🛠️ 代码实现](#🛠️ 代码实现)
- [📊 优缺点分析](#📊 优缺点分析)
- 工厂方法模式
-
- [💡 核心思想](#💡 核心思想)
- [🛠️ 代码实现](#🛠️ 代码实现)
- [📊 优缺点分析](#📊 优缺点分析)
- 抽象工厂模式
-
- [💡 核心思想](#💡 核心思想)
- [🛠️ 代码实现](#🛠️ 代码实现)
- [📊 优缺点分析](#📊 优缺点分析)
- [🧠 总结与对比](#🧠 总结与对比)
🍔 为什么需要工厂模式?
假设你开了一家咖啡店,代码是这样写的:
java
public class CoffeeStore {
public Coffee orderCoffee(String type) {
Coffee coffee = null;
if ("americano".equals(type)) {
coffee = new Americano();
} else if ("latte".equals(type)) {
coffee = new Latte();
}
// 加糖加奶...
return coffee;
}
}
问题来了: 如果现在要加一种卡布奇诺,必须修改 orderCoffee 方法的源码,这违反了开闭原则(对扩展开放,对修改关闭) 。而且,咖啡店不仅负责卖咖啡,还负责生产咖啡,职责不单一。
这时候,我们把生产咖啡的活儿剥离出去,交给专门的工厂来做。
简单工厂模式
简单工厂其实不属于 GoF 23 种设计模式,但它太常用了,可以说是工厂模式的入门。
💡 核心思想
定义一个工厂类,根据传入的参数不同,返回不同的对象实例。
🛠️ 代码实现
java
// 1. 定义咖啡接口
public interface Coffee {
void make();
}
// 2. 具体咖啡实现
public class Americano implements Coffee {
@Override
public void make() {
System.out.println("制作美式咖啡...");
}
}
public class Latte implements Coffee {
@Override
public void make() {
System.out.println("制作拿铁咖啡...");
}
}
// 3. 简单工厂类 (核心)
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {
if ("americano".equals(type)) {
return new Americano();
} else if ("latte".equals(type)) {
return new Latte();
} else {
throw new IllegalArgumentException("没有这种咖啡");
}
}
}
// 4. 咖啡店(客户端)
public class CoffeeStore {
public Coffee orderCoffee(String type) {
// 咖啡店不自己生产,交给工厂
Coffee coffee = SimpleCoffeeFactory.createCoffee(type);
coffee.make();
return coffee;
}
}
📊 优缺点分析
- 优点: 客户端(CoffeeStore)免除了直接创建对象的职责,解除了与具体产品的耦合。
- 缺点: 违背了开闭原则。每增加一种咖啡,都要修改
SimpleCoffeeFactory里的if-else。工厂类的职责过重。
工厂方法模式
为了解决简单工厂违背开闭原则的问题,我们升级一下。
💡 核心思想
定义一个用于创建对象的接口(抽象工厂),让子类决定实例化哪个类。将对象实例化推迟到子类。
🛠️ 代码实现
java
// 1. 抽象工厂接口
public interface CoffeeFactory {
Coffee createCoffee();
}
// 2. 具体工厂实现
public class AmericanoFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new Americano();
}
}
public class LatteFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new Latte();
}
}
// 3. 咖啡店(客户端)
public class CoffeeStore {
// 聚合工厂接口,不再依赖具体工厂
private CoffeeFactory factory;
public CoffeeStore(CoffeeFactory factory) {
this.factory = factory;
}
public Coffee orderCoffee() {
Coffee coffee = factory.createCoffee();
coffee.make();
return coffee;
}
}
客户端调用:
java
// 想喝美式,就开一家美式工厂注入进去
CoffeeStore store = new CoffeeStore(new AmericanoFactory());
store.orderCoffee();
// 想喝拿铁,换一家拿铁工厂
store = new CoffeeStore(new LatteFactory());
store.orderCoffee();
📊 优缺点分析
- 优点: 完美符合开闭原则。新增咖啡种类?只需要新增一个
Coffee实现类和一个对应的CoffeeFactory实现类,完全不用改原有代码! - 缺点: 类的数量成倍增加(每个产品对应一个工厂)。在系统复杂度较低时,这种设计显得有些"重"。
抽象工厂模式
如果现在需求又升级了:咖啡店不仅要卖咖啡,还要卖甜点 !而且美式要配提拉米苏,拿铁要配抹茶蛋糕(它们是有组合关系的)。
这时候用工厂方法就需要建一堆工厂,管理起来很乱。抽象工厂登场!
💡 核心思想
提供一个创建一系列相关或相互依赖对象的接口,而不指定它们具体的类。
🛠️ 代码实现
java
// 1. 定义甜点接口
public interface Dessert {
void show();
}
// 2. 具体甜点
public class Tiramisu implements Dessert {
@Override
public void show() { System.out.println("意大利提拉米苏"); }
}
public class MatchaCake implements Dessert {
@Override
public void show() { System.out.println("抹茶蛋糕"); }
}
// 3. 抽象工厂 (现在是产品族的工厂了)
public interface ItalianDessertFactory {
Coffee createCoffee();
Dessert createDessert();
}
// 4. 具体工厂 (美式风味工厂)
public class AmericanStyleFactory implements ItalianDessertFactory {
@Override
public Coffee createCoffee() { return new Americano(); }
@Override
public Dessert createDessert() { return new Tiramisu(); }
}
// 5. 具体工厂 (拿铁风味工厂)
public class LatteStyleFactory implements ItalianDessertFactory {
@Override
public Coffee createCoffee() { return new Latte(); }
@Override
public Dessert createDessert() { return new MatchaCake(); }
}
客户端调用:
java
// 买一套美式风味套餐
ItalianDessertFactory factory = new AmericanStyleFactory();
Coffee coffee = factory.createCoffee();
Dessert dessert = factory.createDessert();
coffee.make();
dessert.show();
📊 优缺点分析
- 优点: 当一个产品族(如咖啡+甜点)需要一起使用时,它能保证客户端始终使用同一个族中的对象。
- 缺点: 规定了所有可能被创建的产品集合,扩展新产品(比如新增"杯子"维度)非常困难,需要修改抽象工厂接口及其所有实现类,严重违背开闭原则。
🧠 总结与对比
别被这三个名字绕晕,记住下面这张表:
| 模式 | 核心特征 | if-else 在哪? |
扩展新产品 | 扩展新产品族 | 适用场景 |
|---|---|---|---|---|---|
| 简单工厂 | 一个具体工厂,生产所有产品 | 在工厂类里 | 需改工厂代码 | 不支持 | 产品少,逻辑简单 |
| 工厂方法 | 一个抽象工厂,每个产品一个具体工厂 | 没有了 | 增加具体工厂即可 | 不支持 | 产品种类经常扩展 |
| 抽象工厂 | 一个抽象工厂,生产一个产品族 | 没有了 | 非常困难 | 增加具体工厂即可 | 固定的产品族体系(如UI换肤) |