第三章 简单工厂模式:定义、结构、实现、优缺点、应用场景
各位好,今天我们聊聊简单工厂模式。说实话,这是我最喜欢用来开讲设计模式的一个模式。为什么?因为它够简单,够直观,而且你想想看,几乎每个项目里都能找到它的影子。我个人习惯把这种模式叫做“代码里的自动售货机”——你投一个硬币(参数),它给你一瓶饮料(对象)。
3.1 定义与核心思想
简单工厂模式,说白了就是用一个专门的类来负责创建对象。客户端不需要知道具体要创建什么类,只需要告诉工厂“我要什么”,工厂就给你什么。
我记得有一次接手一个老项目,里面到处都是 new XXX(),而且这些类还经常变。每次需求一改,就得满世界找那些 new 语句。后来我用简单工厂一重构,整个世界清净了。嗯,这就是它的价值——把变化集中管理。
核心定义:简单工厂模式(Simple Factory Pattern)属于创建型模式,它定义一个工厂类,根据传入的参数动态决定创建哪一种产品类的实例。
3.2 结构组成
这个模式的结构非常清晰,就三个角色:
- 工厂(Factory):负责创建对象的中心。通常是一个静态方法,根据参数返回不同的产品实例。
- 产品接口(Product):定义产品的公共接口,所有具体产品都要实现它。
- 具体产品(ConcreteProduct):实现产品接口的具体类。
你可能会问:“就这么简单?” 对,就这么简单。但别小看它,很多复杂框架的底层都在用这个思路。
3.3 代码实现
光说不练假把式。我们来看一个实际的例子。假设我们要做一个支付系统,支持支付宝和微信支付。
// 产品接口
public interface Payment {
void pay(double amount);
}
// 具体产品:支付宝
public class Alipay implements Payment {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount + "元");
}
}
// 具体产品:微信支付
public class WechatPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount + "元");
}
}
// 工厂类
public class PaymentFactory {
public static Payment createPayment(String type) {
if ("alipay".equalsIgnoreCase(type)) {
return new Alipay();
} else if ("wechat".equalsIgnoreCase(type)) {
return new WechatPay();
} else {
throw new IllegalArgumentException("不支持的支付类型:" + type);
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(100.0);
}
}
个人小技巧:我在项目中通常会把工厂方法设计成静态的,这样调用起来特别方便。但要注意,静态方法不利于扩展和单元测试。如果你需要更灵活,可以考虑用实例方法配合依赖注入。
3.4 优缺点分析
| 优点 | 缺点 |
|---|---|
| 1. 将对象的创建和使用分离,客户端只需关心产品接口 | 1. 工厂类职责过重,一旦出问题整个系统受影响 |
| 2. 新增产品时只需添加具体类和修改工厂逻辑,符合开闭原则吗?嗯…其实不完全符合 | 2. 新增产品需要修改工厂类,违反了开闭原则(对扩展开放,对修改关闭) |
| 3. 代码结构清晰,适合产品种类较少的场景 | 3. 产品种类过多时,工厂逻辑会变得臃肿,难以维护 |
我曾经踩过的坑:有一次我把所有产品创建逻辑都塞进一个工厂,结果产品类型增加到20多种,那个工厂方法变得又臭又长。每次加新产品都得小心翼翼,生怕影响其他分支。后来我改用工厂方法模式才解决了这个问题。所以,简单工厂适合产品种类少且变化不频繁的场景,别贪心。
3.5 应用场景
那么,什么时候该用简单工厂呢?我总结了几个典型的场景:
- 日志记录器:根据配置或环境,创建文件日志、数据库日志、控制台日志等。
- 数据库访问层:根据数据库类型(MySQL、PostgreSQL、Oracle)创建对应的数据访问对象。
- UI组件创建:根据平台类型(Windows、macOS、Linux)创建不同风格的按钮、文本框。
- 支付网关:就像我们上面的例子,根据支付方式创建对应的支付处理器。
- 文件解析器:根据文件扩展名(.json、.xml、.csv)创建对应的解析器。
你发现没有?这些场景都有一个共同点:客户端需要根据某个条件来创建不同的对象,而且这些对象都实现了相同的接口。这时候,简单工厂就是你的好帮手。
3.6 与其它模式的关系
简单工厂其实不是一个正式的 GoF 设计模式,它更像是一种编程习惯。但它为学习更复杂的工厂模式(工厂方法、抽象工厂)打下了基础。
我个人觉得,简单工厂是“工厂三兄弟”里最接地气的一个。你想想看,工厂方法模式其实就是把简单工厂的“判断逻辑”放到了子类里,而抽象工厂模式则是创建一组相关的产品。但不管怎么变,核心思想都是一样的:把创建对象这件事,交给专门的人去干。
一句话总结:简单工厂模式就是“一个工厂管所有”,适合产品少、变化少的场景。别把它用在大而全的系统里,否则你会后悔的——嗯,我替你们试过了。