揭秘设计模式:工厂模式的五级进化之路
嘿,朋友!你是不是也遇到过代码里满是 new
关键字,每次加个新功能都得改一大堆老代码的窘境?别担心,这几乎是每个程序员的必经之路。今天,我就带你走一趟工厂模式的进化之旅,从最基础的"硬编码"到高手常用的"自动化"工厂,保证让你豁然开朗,写出更优雅、更易于扩展的代码。
第 0 级:原始时代------硬编码的痛
一开始,我们都喜欢简单粗暴。比如,给咖啡馆写个订单系统,顾客点什么,我们就直接在代码里 new
一个对应的对象。
代码长这样:
Java
csharp
public class OrderService {
public void takeOrder(String coffeeType) {
Coffee coffee;
if ("americano".equals(coffeeType)) {
coffee = new Americano();
} else if ("latte".equals(coffeeType)) {
coffee = new Latte();
}
coffee.prepare();
}
}
问题显而易见:
- 一改全动 :想加个新咖啡?对不起,你得去改
OrderService
的老代码。这就像往一栋建好的房子里塞新房间,风险太大。 - 职责混乱 :
OrderService
的本职是处理订单,而不是操心怎么制作咖啡。它现在既是服务员又是咖啡师,分工不明确。
第 1 级:启蒙时代------简单工厂
为了解决这个痛点,我们把创建咖啡的活儿交给一个专门的"咖啡机"------简单工厂。
核心思想:用一个专门的工厂类来统一管理对象的创建。
UML 图:

java
// 简单工厂
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {
if ("americano".equals(type)) {
return new Americano();
} else if ("latte".equals(type)) {
return new Latte();
}
return null;
}
}
// 客户端代码
public class OrderService {
public void takeOrder(String coffeeType) {
Coffee coffee = SimpleCoffeeFactory.createCoffee(coffeeType);
if (coffee != null) {
coffee.prepare();
}
}
}
适用场景:
- 产品数量少且稳定:当你的应用只有少数几种产品,并且这些产品类型很少变动时,简单工厂是最高效的选择。
不足:
- 工厂臃肿 :如果咖啡种类越来越多,
CoffeeFactory
里的if-else
链会越来越长,变成一个难以维护的"巨无霸"。
第 2 级:工业时代------工厂方法
当咖啡馆的菜单每周都更新时,简单工厂的弊端就暴露了。我们得想个更灵活的办法。
核心思想:让每个产品都有自己的专属工厂。
UML 图:

java
// 抽象工厂接口
public interface CoffeeFactory {
Coffee createCoffee();
}
// 具体工厂
public class AmericanoFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new Americano();
}
}
public class LatteFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new Latte();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
CoffeeFactory factory = new AmericanoFactory();
Coffee coffee = factory.createCoffee();
coffee.prepare();
}
}
适用场景:
- 需要频繁添加新产品:当你的应用需要经常扩展新的产品类型,并且希望在不修改旧代码的情况下实现。
不足:
- 类太多:每加一个产品就多两个类(产品和工厂),项目文件列表会越来越长。
- 无法创建套餐:如果你想卖"咖啡+甜点"的套餐,工厂方法就无能为力了。
第 3 级:连锁经营------抽象工厂
我们的咖啡馆现在有了套餐服务:美式套餐配芝士蛋糕,拿铁套餐配曲奇。这些产品需要成套生产。
核心思想 :一个工厂负责创建一整套相关产品。
UML 图:

java
// 抽象产品
public interface Dessert { void serve(); }
public class Cheesecake implements Dessert { ... }
public class Cookie implements Dessert { ... }
// 抽象工厂
public interface ComboFactory {
Coffee createCoffee();
Dessert createDessert();
}
// 具体工厂
public class AmericanoComboFactory implements ComboFactory {
@Override
public Coffee createCoffee() { return new Americano(); }
@Override
public Dessert createDessert() { return new Cheesecake(); }
}
适用场景:
- 创建一系列相关或相互依赖的对象:当你的系统需要创建一整套"产品族",并且这些产品必须一起使用时。
不足:
- 扩展性受限 :如果需要新增一个产品种类(如"小食"),你必须修改所有抽象工厂和具体工厂,工作量不小。
- 客户端依赖具体工厂:客户端代码仍然需要知道具体工厂的类名。
第 4 级:自动化时代------注册式工厂
现在,我们希望我们的系统足够智能,能根据配置文件动态选择工厂,让代码彻底告别 new
的烦恼。
核心思想:用一个中央注册中心来管理所有工厂。
UML 图:

java
// 工厂注册中心(单例模式实现)
public class FactoryRegistry {
private static final Map<String, ComboFactory> factories = new HashMap<>();
public static void register(String name, ComboFactory factory) {
factories.put(name, factory);
}
public static ComboFactory getFactory(String name) {
return factories.get(name);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 程序启动时注册所有工厂
FactoryRegistry.register("americano_combo", new AmericanoComboFactory());
FactoryRegistry.register("latte_combo", new LatteComboFactory());
// 客户端通过名称获取工厂,完全不依赖具体类名
ComboFactory factory = FactoryRegistry.getFactory("americano_combo");
Coffee coffee = factory.createCoffee();
Dessert dessert = factory.createDessert();
}
}
适用场景:
- 运行时动态加载:需要在运行时动态地选择和创建工厂,例如根据配置文件或用户输入来决定使用哪种工厂。
- 彻底解耦:当需要将客户端与具体工厂类彻底解耦时,以实现更强的可扩展性和可维护性。
开发框架与业务中的应用
你可能觉得这些理论听起来很酷,但离实际工作很远。其实不然,工厂模式无处不在。
- Spring Framework :Spring 的核心就是工厂模式的集大成者。它的 IoC 容器 (比如
ApplicationContext
)就是一个超级工厂,负责管理、创建和装配所有对象(bean)。你只需要通过注解或配置告诉它怎么做,剩下的事情它都帮你搞定。 - 支付系统:一个好的支付系统会为每个支付渠道(支付宝、微信、银联)设计一个抽象工厂,用来创建各自的支付网关、签名工具等。想接入一个新的支付渠道?轻松!加一套新的工厂实现就行。
- 跨平台 GUI 开发 :在跨平台图形用户界面(GUI)框架中,抽象工厂模式 用于创建不同操作系统的组件族。例如,一个
GUIFactory
接口可能包含createButton()
和createCheckbox()
方法。在 Windows 上,使用WindowsGUIFactory
来创建WindowsButton
和WindowsCheckbox
;在 macOS 上,则使用MacOSGUIFactory
来创建MacOSButton
和MacOSCheckbox
。
总结:
- 没有银弹:别为了用模式而用。如果项目简单,一个简单工厂就足够了。过度设计反而会增加复杂性。
- 关注扩展点:在设计之初,就想清楚哪些地方未来可能会变,把这些变化点封装起来,通常就是工厂模式的用武之地。
- 别害怕多写代码 :工厂模式确实会增加一些类,但这些额外的代码换来的是更强的可维护性 和扩展性。这是非常值得的投入。