本文目录导读:

- 目录导读
- 工厂模式为什么重要?
- 简单工厂模式 —— 最直观的“制造车间”案例
- 工厂方法模式 —— 让子类决定实例化哪个类(支付场景实战)
- 抽象工厂模式 —— 打造“产品族”的终极方案(跨平台UI案例)
- 三大工厂模式对比与选型决策表
- 高频面试问答与常见坑
- 如何在实际项目中优雅落地工厂模式
目录导读
- 工厂模式为什么重要?—— 解耦与扩展的基石
- 简单工厂模式 —— 最直观的“制造车间”案例(含代码)
- 工厂方法模式 —— 让子类决定实例化哪个类(支付场景实战)
- 抽象工厂模式 —— 打造“产品族”的终极方案(跨平台UI案例)
- 三大工厂模式对比与选型决策表
- 高频面试问答与常见坑(含设计原则分析)
- 如何在实际项目中优雅落地工厂模式
工厂模式为什么重要?
在Java开发中,new关键字是最直接的创建对象方式,但硬编码具体类会导致模块间的紧耦合,工厂模式的核心价值在于:将对象的创建逻辑封装起来,使客户端代码依赖于抽象接口而非具体实现,这符合“开闭原则”和“依赖倒置原则”。
根据Oracle官方文档及Gof《设计模式》的描述,工厂模式分为三种形态:简单工厂(非23种)、工厂方法、抽象工厂。在实际Spring框架中,BeanFactory就是工厂模式的经典应用,它通过配置文件控制对象创建,实现控制反转。
简单工厂模式 —— 最直观的“制造车间”案例
场景:开发一个日志记录器,支持控制台输出和文件输出两种方式。
// 抽象产品
public interface Logger { void log(String message); }
// 具体产品A
public class ConsoleLogger implements Logger {
public void log(String message) { System.out.println("Console: " + message); }
}
// 具体产品B
public class FileLogger implements Logger {
public void log(String message) { System.out.println("File: " + message); }
}
// 简单工厂(Static Factory)
public class LoggerFactory {
public static Logger createLogger(String type) {
if ("console".equalsIgnoreCase(type)) return new ConsoleLogger();
else if ("file".equalsIgnoreCase(type)) return new FileLogger();
throw new IllegalArgumentException("Unknown logger type");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Logger logger = LoggerFactory.createLogger("file");
logger.log("订单创建成功");
}
}
分析:简单工厂将创建逻辑集中在一个类中,客户端只需传入参数,缺点是新增产品需要修改工厂类,违背开闭原则,适合产品类型极少的场景。
工厂方法模式 —— 让子类决定实例化哪个类(支付场景实战)
场景:电商系统支持支付宝和微信支付,不同支付方式有不同初始化流程。
// 抽象产品
public interface Payment { void pay(double amount); }
// 具体产品
public class Alipay implements Payment {
public void pay(double amount) { /* 支付宝SDK调用 */ }
}
public class WechatPay implements Payment {
public void pay(double amount) { /* 微信SDK调用 */ }
}
// 抽象工厂
public abstract class PaymentFactory {
public abstract Payment createPayment();
// 模板方法:公共流程
public void processPayment(double amount) {
Payment payment = createPayment();
payment.pay(amount);
// 记录审计日志...
}
}
// 具体工厂:每个工厂负责一个产品
public class AlipayFactory extends PaymentFactory {
public Payment createPayment() { return new Alipay(); }
}
public class WechatPayFactory extends PaymentFactory {
public Payment createPayment() { return new WechatPay(); }
}
// 客户端:通过工厂实例获取
public class OrderService {
private PaymentFactory paymentFactory;
public OrderService(PaymentFactory factory) { this.paymentFactory = factory; }
public void checkout(double amount) {
paymentFactory.processPayment(amount);
}
}
分析:工厂方法模式将“创建”延迟到子类,客户端可以针对抽象工厂编程,在运行时动态切换具体实现,新增支付方式只需新增一个具体工厂类,完全不修改已有代码。
抽象工厂模式 —— 打造“产品族”的终极方案(跨平台UI案例)
场景:开发一个跨平台UI组件库,需要为Windows和Mac系统分别生成风格匹配的“按钮(Button)”和“文本框(Text)”。
// 抽象产品族
public interface Button { void render(); }
public interface TextField { void show(); }
// Windows产品族
public class WinButton implements Button { public void render() { /* 经典样式 */ } }
public class WinTextField implements TextField { public void show() { /* Windows风格 */ } }
// Mac产品族
public class MacButton implements Button { public void render() { /* 圆角样式 */ } }
public class MacTextField implements TextField { public void show() { /* Mac风格 */ } }
// 抽象工厂:声明创建一组相关产品的方法
public interface UIFactory {
Button createButton();
TextField createTextField();
}
// 具体工厂:维护整个产品族的兼容性
public class WinFactory implements UIFactory {
public Button createButton() { return new WinButton(); }
public TextField createTextField() { return new WinTextField(); }
}
public class MacFactory implements UIFactory {
public Button createButton() { return new MacButton(); }
public TextField createTextField() { return new MacTextField(); }
}
// 客户端:只需绑定一个工厂,保证UI风格统一
public class Application {
private final UIFactory factory;
public Application(UIFactory factory) { this.factory = factory; }
public void buildUI() {
Button b = factory.createButton();
TextField t = factory.createTextField();
// 组合布局...
}
}
分析:抽象工厂确保同一产品族之间的相互兼容(不会出现Windows按钮配Mac文本框),它比工厂方法更抽象、更大型,适合处理多系列产品。
三大工厂模式对比与选型决策表
| 模式 | 核心思想 | 新增单个产品 | 新增整个产品族 | 使用场景 |
|---|---|---|---|---|
| 简单工厂 | 集中式 switch/if | 修改工厂类 | 不支持 | 产品类型少且稳定 |
| 工厂方法 | 每个具体产品对应一个工厂 | 新增一个类 | 不可直接支持 | 单个产品线,扩展频繁 |
| 抽象工厂 | 工厂负责创建一组相关产品 | 修改抽象接口 | 新增一族类 | 跨平台、多主题等产品族场景 |
选型建议:如果只针对一种产品维度,首选工厂方法;若涉及多维度约束(如平台+外观),使用抽象工厂。注意避免过度设计:简单工厂能解决时不必强行使用抽象工厂。
高频面试问答与常见坑
Q1:工厂模式与策略模式的区别?
- 工厂模式:创建对象,主要解决“如何创建”。
- 策略模式:替换行为,主要解决“如何运行”,工厂通常结合策略来实现配置化策略切换。
Q2:Spring中BeanFactory和FactoryBean有什么区别?
- BeanFactory是IoC容器的根接口,负责管理Bean生命周期。
- FactoryBean是一个特殊Bean,自身作为工厂用来生产其他对象(典型的工厂方法模式应用)。
Q3:工厂模式如何违反依赖倒置原则?
- 简单工厂中,客户端依赖于具体工厂类,建议客户端依赖抽象接口,工厂本身纳入接口管理。
常见坑:
- 过度使用:产品种类固定且无扩展需求时,工厂反而增加复杂度。
- 静态工厂方法无法被继承:导致无法通过子类定制工厂行为。
- 多线程环境下未考虑线程安全:创建昂贵对象时应考虑双重检查锁或单例工厂。
如何在实际项目中优雅落地工厂模式
工厂模式并非银弹。合理的做法是“由重构而来,而非预先设计”,当发现代码中存在大量重复的new或switch条件判断出现增长趋势时,才将该处重构为工厂模式。
比如在微服务架构中,通过工厂类配合配置中心,可以动态创建不同类型的消息发送器(短信、邮件、推送),让业务代码完全不感知具体实现,结合反射和枚举,可以构建“可扩展免修改”的简单工厂,大大提升灵活性。
请务必记住:工厂模式的核心是封装变化,而不是滥用接口,在团队中统一设计规范,并在代码评审时关注创建逻辑的耦合度,才能真正发挥其威力。
(文章结束)