什么是抽象工厂模式
抽象工厂模式是一种创建型设计模式,它提供一个接口来创建一系列相关或相互依赖的对象家族,而无需指定它们的具体类。简单来说,抽象工厂模式是工厂模式的升级版,它不再只生产一种产品,而是生产一整套产品。
抽象工厂vs工厂方法:关键区别
- 工厂方法模式 :关注单个产品的创建,一个工厂创建一种产品
- 抽象工厂模式 :关注产品族的创建,一个工厂创建多种相关产品
这就像一个生产手机的工厂(工厂方法)和一个生产整套电子设备(手机、平板、耳机)的工厂(抽象工厂)的区别。
抽象工厂模式的核心实现
java
// 产品A接口
public interface ProductA {
void operationA();
}
// 产品B接口
public interface ProductB {
void operationB();
}
// 产品A1实现
public class ConcreteProductA1 implements ProductA {
@Override
public void operationA() {
System.out.println("产品A1的操作");
}
}
// 产品A2实现
public class ConcreteProductA2 implements ProductA {
@Override
public void operationA() {
System.out.println("产品A2的操作");
}
}
// 产品B1实现
public class ConcreteProductB1 implements ProductB {
@Override
public void operationB() {
System.out.println("产品B1的操作");
}
}
// 产品B2实现
public class ConcreteProductB2 implements ProductB {
@Override
public void operationB() {
System.out.println("产品B2的操作");
}
}
// 抽象工厂接口
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1 - 创建产品族1(A1+B1)
public class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2 - 创建产品族2(A2+B2)
public class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
抽象工厂模式的关键点
- 产品接口:为每种产品定义接口
- 具体产品:实现产品接口的具体类
- 抽象工厂接口:声明一组创建产品的方法
- 具体工厂:实现抽象工厂接口,创建一个产品族
- 产品族:一组相关产品的集合(例如PC系列组件、移动系列组件)
实际应用示例:跨平台UI组件库
下面通过一个跨平台UI组件库的例子来展示抽象工厂模式的强大应用:
java
// ===== 按钮组件 =====
public interface Button {
void render();
void onClick();
}
// Windows按钮
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("渲染Windows风格的按钮");
}
@Override
public void onClick() {
System.out.println("Windows按钮点击效果");
}
}
// MacOS按钮
public class MacOSButton implements Button {
@Override
public void render() {
System.out.println("渲染MacOS风格的按钮");
}
@Override
public void onClick() {
System.out.println("MacOS按钮点击效果");
}
}
// ===== 复选框组件 =====
public interface Checkbox {
void render();
void toggle();
}
// Windows复选框
public class WindowsCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("渲染Windows风格的复选框");
}
@Override
public void toggle() {
System.out.println("Windows复选框切换状态");
}
}
// MacOS复选框
public class MacOSCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("渲染MacOS风格的复选框");
}
@Override
public void toggle() {
System.out.println("MacOS复选框切换状态");
}
}
// ===== 文本框组件 =====
public interface TextField {
void render();
void getText();
}
// Windows文本框
public class WindowsTextField implements TextField {
@Override
public void render() {
System.out.println("渲染Windows风格的文本框");
}
@Override
public void getText() {
System.out.println("获取Windows文本框内容");
}
}
// MacOS文本框
public class MacOSTextField implements TextField {
@Override
public void render() {
System.out.println("渲染MacOS风格的文本框");
}
@Override
public void getText() {
System.out.println("获取MacOS文本框内容");
}
}
// ===== GUI工厂接口 =====
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
TextField createTextField();
}
// Windows GUI工厂
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
// MacOS GUI工厂
public class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public Checkbox createCheckbox() {
return new MacOSCheckbox();
}
@Override
public TextField createTextField() {
return new MacOSTextField();
}
}
如何使用抽象工厂模式
java
// 应用类 - 与具体工厂解耦
public class Application {
private Button button;
private Checkbox checkbox;
private TextField textField;
// 构造函数接收一个抽象工厂
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
textField = factory.createTextField();
}
// 渲染表单
public void renderForm() {
System.out.println("=== 开始渲染表单 ===");
button.render();
checkbox.render();
textField.render();
System.out.println("=== 表单渲染完成 ===");
}
// 表单操作
public void handleForm() {
System.out.println("\n=== 表单交互 ===");
button.onClick();
checkbox.toggle();
textField.getText();
}
}
// 客户端代码
public class GUIDemo {
public static void main(String[] args) {
// 检测当前操作系统
String osName = System.getProperty("os.name").toLowerCase();
GUIFactory factory;
// 根据操作系统选择合适的工厂
if (osName.contains("windows")) {
factory = new WindowsFactory();
System.out.println("检测到Windows系统,使用Windows风格UI");
} else {
factory = new MacOSFactory();
System.out.println("检测到非Windows系统,使用MacOS风格UI");
}
// 创建并使用应用 - 注意应用不依赖于具体组件类
Application app = new Application(factory);
app.renderForm();
app.handleForm();
}
}
运行结果(Windows系统上)
diff
检测到Windows系统,使用Windows风格UI
=== 开始渲染表单 ===
渲染Windows风格的按钮
渲染Windows风格的复选框
渲染Windows风格的文本框
=== 表单渲染完成 ===
=== 表单交互 ===
Windows按钮点击效果
Windows复选框切换状态
获取Windows文本框内容
运行结果(MacOS系统上)
diff
检测到非Windows系统,使用MacOS风格UI
=== 开始渲染表单 ===
渲染MacOS风格的按钮
渲染MacOS风格的复选框
渲染MacOS风格的文本框
=== 表单渲染完成 ===
=== 表单交互 ===
MacOS按钮点击效果
MacOS复选框切换状态
获取MacOS文本框内容
抽象工厂模式的常见应用场景
- 跨平台UI工具包:为不同操作系统提供一致的界面组件
- 数据库访问层:支持多种数据库系统(MySQL、Oracle、MongoDB等)
- 游戏开发:创建不同主题的游戏元素(中世纪、未来、童话等)
- 多环境配置系统:为开发、测试、生产环境提供不同实现
- 电子设备生态系统:创建配套的产品(手机、耳机、手表都来自同一品牌)
- 多主题应用:切换应用的视觉主题(暗色模式/亮色模式)
抽象工厂模式的实际案例
许多知名框架和库使用抽象工厂模式,如:
- Java的JDBC :
ConnectionFactory
创建特定数据库的连接 - Spring Framework:通过BeanFactory创建和管理各种组件
- javax.xml.parsers.DocumentBuilderFactory:创建DOM解析器
- Hibernate :
SessionFactory
为不同数据库创建会话
抽象工厂模式的优点
- 产品一致性保证:确保一个工厂创建的产品相互兼容
- 隔离具体类:客户端与具体类隔离,只与接口交互
- 开闭原则:引入新产品族不需要修改现有代码
- 替换产品族:可以整体替换产品族(如UI主题切换)
抽象工厂模式的缺点
- 扩展困难:添加新的产品类型需要修改工厂接口及所有实现
- 复杂度增加:产品较多时,类的数量会急剧增加
- 接口污染:接口中可能包含部分工厂不支持的创建方法
抽象工厂的实现变体
使用反射简化工厂实现
java
public class ReflectiveFactory implements GUIFactory {
private String packageName;
public ReflectiveFactory(String stylePrefix) {
packageName = "com.example.gui." + stylePrefix.toLowerCase();
}
@Override
public Button createButton() {
return (Button) createComponent("Button");
}
@Override
public Checkbox createCheckbox() {
return (Checkbox) createComponent("Checkbox");
}
@Override
public TextField createTextField() {
return (TextField) createComponent("TextField");
}
private Object createComponent(String type) {
try {
Class<?> clazz = Class.forName(packageName + "." + type);
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("无法创建组件", e);
}
}
}
带有默认实现的抽象工厂
java
public abstract class BaseGUIFactory implements GUIFactory {
// 提供默认实现
@Override
public TextField createTextField() {
return new DefaultTextField(); // 所有平台通用的默认实现
}
// 其他方法需要子类实现
@Override
public abstract Button createButton();
@Override
public abstract Checkbox createCheckbox();
}
实现抽象工厂的设计考虑
- 产品族边界:明确定义哪些产品属于同一族
- 接口设计:保持工厂接口精简,避免方法爆炸
- 工厂选择机制:考虑如何选择/切换具体工厂
- 扩展策略:提前考虑如何添加新产品类型
- 组合与单一职责:大型产品族可考虑拆分为多个子工厂
抽象工厂模式最佳实践
- 适度使用:当确实需要创建一系列相关对象时才使用
- 懒加载:考虑延迟创建产品,而不是一次创建所有产品
- 结合其他模式:与单例、原型、构建者等模式结合使用
- 依赖注入:通过依赖注入框架传递工厂
- 配置驱动:使用配置文件或注解选择具体工厂实现
java
// 使用配置驱动的工厂
public class ConfigurableGUIFactory {
public static GUIFactory getFactory() {
String factoryType = ConfigLoader.getProperty("ui.factory");
switch (factoryType) {
case "windows": return new WindowsFactory();
case "macos": return new MacOSFactory();
case "web": return new WebFactory();
default: throw new IllegalArgumentException("未知UI工厂类型");
}
}
}
抽象工厂与依赖倒置原则
抽象工厂是实现依赖倒置原则的绝佳方式:高层模块不依赖于低层模块,两者都依赖于抽象。
java
// 不好的设计:直接依赖具体类
public class BadForm {
private WindowsButton button; // 直接依赖具体实现
private WindowsCheckbox checkbox;
public void createUI() {
button = new WindowsButton(); // 硬编码创建具体类
checkbox = new WindowsCheckbox();
}
}
// 好的设计:依赖抽象
public class GoodForm {
private Button button; // 依赖接口
private Checkbox checkbox;
private final GUIFactory factory; // 依赖抽象工厂
public GoodForm(GUIFactory factory) {
this.factory = factory;
}
public void createUI() {
button = factory.createButton(); // 通过工厂创建
checkbox = factory.createCheckbox();
}
}
抽象工厂模式小结
抽象工厂模式是一种强大但需谨慎使用的创建型模式。它在需要一套相关产品且系统不应依赖于产品的具体类时非常有用。这种模式有助于确保产品兼容性,并为产品族提供统一的创建接口。
适当应用抽象工厂模式可以使代码更具灵活性和可维护性,但也要避免过度设计导致的复杂性。理解产品族的概念和如何设计良好的抽象工厂接口是掌握这一模式的关键。