工厂模式:对象创建的智慧之道
引言:为什么我们需要工厂模式?
在软件开发中,对象创建是最常见的操作之一 。当代码中充满new
关键字时,系统会面临三大痛点:
- 紧耦合:客户端代码直接依赖具体实现类
- 扩展困难:新增产品类型需修改多处代码
- 职责混乱:业务逻辑与对象创建逻辑混杂
工厂模式(Factory Pattern)正是解决这些问题的创建型设计模式 。它通过定义对象创建接口,让子类决定实例化哪个类,实现创建逻辑与使用逻辑的解耦。
工厂模式家族包含三种形态:简单工厂 、工厂方法 和抽象工厂,各自解决不同层次的问题。
一、简单工厂模式(静态工厂)
1.1 基础概念
classDiagram
class Client
class SimpleFactory {
+createProduct(String type) Product
}
interface Product {
+use()
}
class ConcreteProductA
class ConcreteProductB
Client --> SimpleFactory
SimpleFactory ..> Product
Product <|.. ConcreteProductA
Product <|.. ConcreteProductB
1.2 代码实现
java
// 产品接口
interface Button {
void render();
}
// 具体产品
class WindowsButton implements Button {
public void render() {
System.out.println("渲染Windows风格按钮");
}
}
class MacOSButton implements Button {
public void render() {
System.out.println("渲染MacOS风格按钮");
}
}
// 简单工厂
class ButtonFactory {
public static Button createButton(String osType) {
if ("windows".equalsIgnoreCase(osType)) {
return new WindowsButton();
} else if ("macos".equalsIgnoreCase(osType)) {
return new MacOSButton();
}
throw new IllegalArgumentException("未知操作系统类型");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Button btn = ButtonFactory.createButton("macos");
btn.render(); // 输出:渲染MacOS风格按钮
}
}
1.3 适用场景与局限
适用场景:
- 产品种类有限且固定
- 客户端不关心创建细节
缺点:
- 违反开闭原则(新增产品需修改工厂)
- 工厂类职责过重
二、工厂方法模式(多态工厂)
2.1 核心思想
classDiagram
class Client
interface Factory {
+createButton() Button
}
class WindowsFactory
class MacOSFactory
interface Button
class WindowsButton
class MacOSButton
Client --> Factory
Factory <|.. WindowsFactory
Factory <|.. MacOSFactory
Factory ..> Button
Button <|.. WindowsButton
Button <|.. MacOSButton
2.2 代码实现
java
// 抽象工厂
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具体工厂
class WindowsFactory implements GUIFactory {
public Button createButton() {
return new WindowsButton();
}
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
class MacOSFactory implements GUIFactory {
public Button createButton() {
return new MacOSButton();
}
public Checkbox createCheckbox() {
return new MacOSCheckbox();
}
}
// 客户端代码
public class Application {
private Button button;
private Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void render() {
button.render();
checkbox.render();
}
}
// 使用示例
public class Demo {
public static void main(String[] args) {
GUIFactory factory;
if (System.getProperty("os.name").contains("Windows")) {
factory = new WindowsFactory();
} else {
factory = new MacOSFactory();
}
Application app = new Application(factory);
app.render();
}
}
2.3 模式优势
- 完全符合开闭原则:新增产品只需添加新工厂
- 单一职责原则:每个工厂只负责一类产品
- 可测试性:可通过Mock工厂进行单元测试
三、抽象工厂模式(产品族工厂)
3.1 解决复杂产品族创建
classDiagram
class Client
interface AbstractFactory {
+createButton() Button
+createCheckbox() Checkbox
}
class ModernFactory
class VintageFactory
interface Button
interface Checkbox
class ModernButton
class VintageButton
class ModernCheckbox
class VintageCheckbox
Client --> AbstractFactory
AbstractFactory <|.. ModernFactory
AbstractFactory <|.. VintageFactory
AbstractFactory ..> Button
AbstractFactory ..> Checkbox
Button <|.. ModernButton
Button <|.. VintageButton
Checkbox <|.. ModernCheckbox
Checkbox <|.. VintageCheckbox
3.2 跨平台UI案例
java
// 抽象产品族
interface Button {
void render();
}
interface Checkbox {
void toggle();
}
// 现代风格产品
class ModernButton implements Button {
public void render() {
System.out.println("渲染扁平化按钮");
}
}
class ModernCheckbox implements Checkbox {
public void toggle() {
System.out.println("切换Material Design复选框");
}
}
// 复古风格产品
class VintageButton implements Button {
public void render() {
System.out.println("渲染拟物化按钮");
}
}
class VintageCheckbox implements Checkbox {
public void toggle() {
System.out.println("切换复古风格复选框");
}
}
// 抽象工厂
interface UIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具体工厂
class ModernUIFactory implements UIFactory {
public Button createButton() {
return new ModernButton();
}
public Checkbox createCheckbox() {
return new ModernCheckbox();
}
}
class VintageUIFactory implements UIFactory {
public Button createButton() {
return new VintageButton();
}
public Checkbox createCheckbox() {
return new VintageCheckbox();
}
}
// 配置类(决定使用哪种风格)
class UIStyleConfig {
public static UIFactory getFactory(String style) {
if ("modern".equals(style)) {
return new ModernUIFactory();
} else if ("vintage".equals(style)) {
return new VintageUIFactory();
}
throw new IllegalArgumentException("未知UI风格");
}
}
3.3 模式特点
优势:
- 保证产品族兼容性(如统一风格的UI组件)
- 切换产品族只需替换工厂实例
局限性:
- 新增产品类型需修改所有工厂接口
- 类数量指数级增长(产品族×产品类型)
四、三大工厂模式对比
特性 | 简单工厂 | 工厂方法 | 抽象工厂 |
---|---|---|---|
创建对象范围 | 单一产品 | 单一产品 | 产品族 |
开闭原则支持 | ❌ 修改工厂类 | ✅ 扩展新工厂 | ✅ 扩展新工厂 |
复杂度 | ★☆☆ 简单 | ★★☆ 中等 | ★★★ 复杂 |
适用场景 | 固定类型产品 | 单一类型产品扩展 | 相关产品组成的家族 |
系统扩展方向 | 垂直扩展(修改代码) | 水平扩展(新增工厂) | 水平扩展(新增产品族) |
五、工厂模式在框架中的实践
5.1 JDK中的工厂模式
java
// 工厂方法示例
Calendar cal = Calendar.getInstance(); // 根据时区创建实例
// 抽象工厂示例
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
5.2 Spring框架的工厂应用
java
// BeanFactory:顶级工厂接口
BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");
MyService service = factory.getBean(MyService.class);
// FactoryBean:定制复杂对象创建
public class MyFactoryBean implements FactoryBean<Connection> {
public Connection getObject() {
return DriverManager.getConnection(...);
}
}
5.3 Log4j2的日志工厂
java
Logger logger = LogManager.getLogger(); // 获取日志器工厂
六、工厂模式最佳实践
6.1 何时使用工厂模式?
- 系统需要支持多种实现变体(如不同数据库驱动)
- 需要隔离创建逻辑与业务代码
- 需要统一管理对象生命周期
- 实现可插拔架构(运行时切换实现)
6.2 设计原则落地
- 开闭原则:通过扩展而非修改增加功能
- 依赖倒置:依赖抽象而非具体实现
- 单一职责:创建逻辑与业务逻辑分离
6.3 避免常见误区
- 过度设计 :简单场景直接使用
new
- 工厂膨胀:当产品类型过多时考虑重构
- 循环依赖:工厂之间避免相互调用
七、工厂模式演进与变种
7.1 静态工厂方法
java
// JDK中的经典案例
List<String> list = Collections.unmodifiableList(originalList);
7.2 参数化工厂
java
class VehicleFactory {
Vehicle createVehicle(VehicleType type, String model) {
switch(type) {
case CAR: return new Car(model);
case TRUCK: return new Truck(model);
}
}
}
7.3 延迟初始化工厂
java
class LazyFactory {
private Map<String, Product> cache = new HashMap<>();
Product getProduct(String key) {
if (!cache.containsKey(key)) {
cache.put(key, createProduct(key));
}
return cache.get(key);
}
}
八、工厂模式经典面试题
Q1:工厂方法和抽象工厂的核心区别?
答案:
- 工厂方法关注单一产品的创建
- 抽象工厂关注相关产品族的创建
- 抽象工厂通常包含多个工厂方法
Q2:Spring中的BeanFactory和FactoryBean有何不同?
答案:
BeanFactory | FactoryBean |
---|---|
基础IoC容器 | 创建复杂对象的工厂接口 |
管理所有Bean的生命周期 | 定制特殊Bean的创建过程 |
通过getBean()获取对象 | 实现getObject()返回目标对象 |
结语:工厂模式的价值思考
工厂模式不仅是技术实现,更是架构思维的体现。它教会我们:
- 解耦的艺术:分离变与不变的部分
- 扩展的智慧:通过组合而非修改扩展系统
- 抽象的边界:合理划分职责边界
在微服务和云原生时代,工厂模式演变为:
- 依赖注入:更高级的对象装配方式
- 服务工厂:动态服务实例创建(如gRPC)
- 云资源工厂:按需创建云资源(AWS/Aliyun SDK)
最后提醒: 不要为了模式而模式!当创建逻辑确实存在变体时,再引入工厂模式。