流水线上的艺术:揭秘Java工厂模式的套娃哲学
一、当new对象成为「高危操作」
你是否经历过这样的抓狂时刻?客户端代码里遍布new XXXServiceImpl(),每次切换实现类就像在雷区跳踢踏舞;当需要创建复杂对象时,构造代码长得能绕地球三圈——恭喜你,已经踩中了工厂模式的启动开关。
工厂模式宣言:
把对象创建这个危险动作关进笼子!客户端不需要知道对象是怎么拼装的,就像吃汉堡的人不需要认识养牛场老板。
二、工厂流水线的设计图(UML全家桶)
1. 简单工厂:新手村流水线
┌─────────────┐ ┌───────────┐
│ Client │------>│ Factory │
└─────────────┘ ├───────────┤
│createProduct()
└─────┬─────┘
▼
┌───────────────────┐
│ Product │
├───────────────────┤
│ +use() │
└─────────┬─────────┘
△
┌─────────────┴─────────────┐
│ │
┌─────────────┐ ┌─────────────┐
│ConcreteProdA│ │ConcreteProdB│
└─────────────┘ └─────────────┘
- 厂长(Factory):掌握所有产品的生产秘方
- 产品标准(Product):所有产品必须实现的接口
- 流水线缺陷:每新增产品就要修改厂长代码(违反开闭原则)
2. 工厂方法:特许经营模式
┌─────────────┐ ┌─────────────┐
│ Client │--------->│ Factory │
└─────────────┘ ├─────────────┤
│createProduct()◄──┐
└─────────────┘ │
│
┌─────────────────────────────|
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ ConcreteFactoryA │ │ ConcreteFactoryB │
├───────────────────────┤ ├───────────────────────┤
│ +createProduct() │ │ +createProduct() │
└───────────────────────┘ └───────────────────────┘
- 总部制定标准(Factory接口)
- 加盟商自主生产(具体工厂实现)
- 完美支持新产品线扩展
3. 抽象工厂:工业综合体
┌───────────────────────────────┐
│ AbstractFactory │
├───────────────────────────────┤
│ +createKeyboard() │
│ +createMouse() │
└──────────────┬────────────────┘
△
┌──────────────┴────────────────┐
│ │
┌─────────────────────┐ ┌─────────────────────┐
│ LogitechFactory │ │ RazerFactory │
├─────────────────────┤ ├─────────────────────┤
│ +createKeyboard() │ │ +createKeyboard() │
│ +createMouse() │ │ +createMouse() │
└─────────────────────┘ └─────────────────────┘
- 生产产品族(配套的多个相关产品)
- 切换品牌只需换工厂
- 类爆炸警告(每个产品族都需要新工厂)
三、代码车间实录
1. 简单工厂:if-else大师
// 键盘生产车间
public class KeyboardFactory {
public static Keyboard createKeyboard(String type) {
if("mechanical".equals(type)) {
return new MechanicalKeyboard();
} else if("membrane".equals(type)) {
return new MembraneKeyboard();
}
throw new IllegalArgumentException("臣妾做不到啊");
}
}
// 使用示例
Keyboard k = KeyboardFactory.createKeyboard("mechanical");
2. 工厂方法:家族企业联盟
// 总部标准
interface MouseFactory {
Mouse createMouse();
}
// 罗技分厂
class LogitechFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new LogitechMouse();
}
}
// 雷蛇分厂
class RazerFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new RazerMouse();
}
}
3. 抽象工厂:品牌全家桶
// 3C产品联盟
interface TechFactory {
Phone createPhone();
Laptop createLaptop();
}
// 苹果生态
class AppleFactory implements TechFactory {
public Phone createPhone() { return new iPhone(); }
public Laptop createLaptop() { return new MacBook(); }
}
// 华为生态
class HuaweiFactory implements TechFactory {
public Phone createPhone() { return new MatePhone(); }
public Laptop createLaptop() { return new MateBook(); }
}
四、工厂三兄弟的职场PK
| 维度 | 简单工厂 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 适用场景 | 固定产品线 | 单一产品扩展 | 产品族切换 |
| 扩展代价 | 修改工厂类 | 新增工厂类 | 新增工厂类 |
| 复杂度 | ⭐ | ⭐⭐ | ⭐⭐⭐ |
| 灵活度 | 一次性解决方案 | 支持多态扩展 | 生态系统级切换 |
| 现实类比 | 手工作坊 | 品牌专卖店 | 商业综合体 |
选型指南:
- 产品类型固定 → 简单工厂
- 需要灵活扩展 → 工厂方法
- 成套产品切换 → 抽象工厂
五、走进制造业的春天
- JDBC驱动加载:
DriverManager.getConnection()隐藏了不同数据库的实现 - SLF4J日志门面:背后自动匹配Logback/Log4j2等实现
- Spring BeanFactory:IoC容器的核心生产流水线
- XML解析器选择:DocumentBuilderFactory根据配置生产不同解析器
- 游戏武器系统:��同派系武器使用不同工厂创建
经典语录:
Spring的@Bean注解就是新时代的工厂方法,@Configuration类就是豪华工厂车间。
六、防流水线事故指南
- 不要过度设计:3个类能解决就别用30个类
- 优先组合代替继承:工厂对象可以被注入替换
- 善用枚举优化判断:用枚举消除魔法字符串
- 考虑静态工厂方法:比如
Collections.synchronizedList() - 拥抱现代框架:Spring的
@Component比传统工厂更香
反面教材:
// 地狱级if-else工厂
public class BadFactory {
public static Product create(String type) {
if("A".equals(type)) { /* 50行代码 */ }
else if("B".equals(type)) { /* 50行代码 */ }
// 后续还有50个else if...
}
}
七、厂长总结大会
工厂模式就像代码界的乐高积木:
- 简单工厂是基础套装,适合快速搭建
- 工厂方法是主题扩展包,支持无限创意
- 抽象工厂是城市系列,构建完整生态
记住三个灵魂拷问:
- 你的代码还在到处new对象吗?
- 需求变更时需要修改多少处new?
- 客户端真的需要知道具体实现类吗?
当下次看到Calendar.getInstance()时,请向这位深藏功与名的工厂前辈脱帽致敬!