【设计模式手册022】抽象工厂模式 - 创建产品家族
1. 我们为何需要抽象工厂模式?
在软件设计中,我们经常会遇到这样的场景:需要创建一系列相关或依赖的对象,这些对象构成了一个"产品家族"。比如:
- UI主题系统:浅色主题的按钮、文本框、下拉框 vs 深色主题的按钮、文本框、下拉框
- 跨平台UI:Windows风格的按钮、菜单、对话框 vs Mac风格的按钮、菜单、对话框
- 数据库访问:MySQL的连接、命令、适配器 vs Oracle的连接、命令、适配器
- 游戏引擎:科幻风格的敌人、武器、场景 vs 魔幻风格的敌人、武器、场景
初级程序员的写法:
java
public class LightThemeButton {
public void render() {
System.out.println("渲染浅色主题按钮");
}
}
public class LightThemeTextBox {
public void render() {
System.out.println("渲染浅色主题文本框");
}
}
public class DarkThemeButton {
public void render() {
System.out.println("渲染深色主题按钮");
}
}
public class DarkThemeTextBox {
public void render() {
System.out.println("渲染深色主题文本框");
}
}
// 客户端代码 - 直接创建具体对象
public class Client {
public void createUI(String theme) {
if ("light".equals(theme)) {
LightThemeButton button = new LightThemeButton();
LightThemeTextBox textBox = new LightThemeTextBox();
button.render();
textBox.render();
} else if ("dark".equals(theme)) {
DarkThemeButton button = new DarkThemeButton();
DarkThemeTextBox textBox = new DarkThemeTextBox();
button.render();
textBox.render();
}
// 每新增一个主题,就要修改这里
}
}
这种写法的痛点:
- ❌ 违反开闭原则:新增产品家族需要修改客户端代码
- ❌ 对象创建逻辑分散:创建相关对象的逻辑分散在代码各处
- ❌ 产品一致性难保证:可能错误地混合不同家族的产品
- ❌ 难以扩展:新增产品家族需要修改所有创建代码
2. 抽象工厂模式:本质与定义
2.1 模式定义
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
2.2 模式结构
java
// 抽象产品A
public interface AbstractProductA {
void operationA();
}
// 抽象产品B
public interface AbstractProductB {
void operationB();
}
// 具体产品A1
public class ConcreteProductA1 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("具体产品A1的操作");
}
}
// 具体产品B1
public class ConcreteProductB1 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("具体产品B1的操作");
}
}
// 具体产品A2
public class ConcreteProductA2 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("具体产品A2的操作");
}
}
// 具体产品B2
public class ConcreteProductB2 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("具体产品B2的操作");
}
}
// 抽象工厂
public interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
3. 深入理解
3.1 产品家族的封装
核心思想:将相关产品的创建封装在同一个工厂中,确保产品之间的兼容性。
java
// 不好的做法:客户端直接创建具体产品
public class BadClient {
public void createUI() {
// 可能错误地混合不同家族的产品
LightThemeButton button = new LightThemeButton();
DarkThemeTextBox textBox = new DarkThemeTextBox(); // 不一致!
}
}
// 好的做法:通过工厂创建确保一致性
public class GoodClient {
private AbstractFactory factory;
public GoodClient(AbstractFactory factory) {
this.factory = factory;
}
public void createUI() {
// 工厂保证创建的产品属于同一家族
AbstractProductA productA = factory.createProductA();
AbstractProductB productB = factory.createProductB();
}
}
3.2 工厂的层次结构
设计原则的体现:通过抽象工厂接口,客户端代码与具体产品类解耦。
java
// 客户端只依赖抽象接口
public class Client {
private AbstractFactory factory;
private AbstractProductA productA;
private AbstractProductB productB;
public Client(AbstractFactory factory) {
this.factory = factory;
this.productA = factory.createProductA();
this.productB = factory.createProductB();
}
// 使用产品,不关心具体类型
public void operate() {
productA.operationA();
productB.operationB();
}
}
3.3 动态工厂选择
通过配置或运行时条件动态选择具体工厂。
java
public class FactoryCreator {
public static AbstractFactory createFactory(String type) {
switch (type) {
case "family1":
return new ConcreteFactory1();
case "family2":
return new ConcreteFactory2();
default:
throw new IllegalArgumentException("未知的产品家族: " + type);
}
}
}
4. 实战案例:完整的跨平台UI系统
让我们来看一个完整的例子:
java
// 抽象UI组件
public interface Button {
void render();
void onClick();
}
public interface TextBox {
void render();
void setText(String text);
}
public interface CheckBox {
void render();
void setChecked(boolean checked);
}
// Windows风格组件
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("渲染Windows风格按钮");
}
@Override
public void onClick() {
System.out.println("Windows按钮被点击");
}
}
public class WindowsTextBox implements TextBox {
@Override
public void render() {
System.out.println("渲染Windows风格文本框");
}
@Override
public void setText(String text) {
System.out.println("Windows文本框设置文本: " + text);
}
}
public class WindowsCheckBox implements CheckBox {
@Override
public void render() {
System.out.println("渲染Windows风格复选框");
}
@Override
public void setChecked(boolean checked) {
System.out.println("Windows复选框设置状态: " + checked);
}
}
// Mac风格组件
public class MacButton implements Button {
@Override
public void render() {
System.out.println("渲染Mac风格按钮");
}
@Override
public void onClick() {
System.out.println("Mac按钮被点击");
}
}
public class MacTextBox implements TextBox {
@Override
public void render() {
System.out.println("渲染Mac风格文本框");
}
@Override
public void setText(String text) {
System.out.println("Mac文本框设置文本: " + text);
}
}
public class MacCheckBox implements CheckBox {
@Override
public void render() {
System.out.println("渲染Mac风格复选框");
}
@Override
public void setChecked(boolean checked) {
System.out.println("Mac复选框设置状态: " + checked);
}
}
// Linux风格组件
public class LinuxButton implements Button {
@Override
public void render() {
System.out.println("渲染Linux风格按钮");
}
@Override
public void onClick() {
System.out.println("Linux按钮被点击");
}
}
public class LinuxTextBox implements TextBox {
@Override
public void render() {
System.out.println("渲染Linux风格文本框");
}
@Override
public void setText(String text) {
System.out.println("Linux文本框设置文本: " + text);
}
}
public class LinuxCheckBox implements CheckBox {
@Override
public void render() {
System.out.println("渲染Linux风格复选框");
}
@Override
public void setChecked(boolean checked) {
System.out.println("Linux复选框设置状态: " + checked);
}
}
// 抽象UI工厂
public interface UIFactory {
Button createButton();
TextBox createTextBox();
CheckBox createCheckBox();
}
// 具体UI工厂
public class WindowsUIFactory implements UIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextBox createTextBox() {
return new WindowsTextBox();
}
@Override
public CheckBox createCheckBox() {
return new WindowsCheckBox();
}
}
public class MacUIFactory implements UIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextBox createTextBox() {
return new MacTextBox();
}
@Override
public CheckBox createCheckBox() {
return new MacCheckBox();
}
}
public class LinuxUIFactory implements UIFactory {
@Override
public Button createButton() {
return new LinuxButton();
}
@Override
public TextBox createTextBox() {
return new LinuxTextBox();
}
@Override
public CheckBox createCheckBox() {
return new LinuxCheckBox();
}
}
// 应用类 - 使用抽象工厂
public class Application {
private UIFactory factory;
private Button button;
private TextBox textBox;
private CheckBox checkBox;
public Application(UIFactory factory) {
this.factory = factory;
}
public void createUI() {
System.out.println("创建用户界面...");
this.button = factory.createButton();
this.textBox = factory.createTextBox();
this.checkBox = factory.createCheckBox();
}
public void renderUI() {
System.out.println("渲染用户界面...");
button.render();
textBox.render();
checkBox.render();
}
public void simulateUserInteraction() {
System.out.println("模拟用户交互...");
button.onClick();
textBox.setText("Hello World");
checkBox.setChecked(true);
}
public void displayFactoryInfo() {
String factoryType = factory.getClass().getSimpleName();
System.out.println("当前使用的UI工厂: " + factoryType);
System.out.println("按钮类型: " + button.getClass().getSimpleName());
System.out.println("文本框类型: " + textBox.getClass().getSimpleName());
System.out.println("复选框类型: " + checkBox.getClass().getSimpleName());
}
}
// 工厂创建器
public class UIFactoryCreator {
public enum Platform {
WINDOWS, MAC, LINUX
}
public static UIFactory createFactory(Platform platform) {
switch (platform) {
case WINDOWS:
return new WindowsUIFactory();
case MAC:
return new MacUIFactory();
case LINUX:
return new LinuxUIFactory();
default:
throw new IllegalArgumentException("不支持的平台: " + platform);
}
}
// 根据系统属性自动检测平台
public static UIFactory createFactoryForCurrentPlatform() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) {
return new WindowsUIFactory();
} else if (osName.contains("mac")) {
return new MacUIFactory();
} else if (osName.contains("nix") || osName.contains("nux")) {
return new LinuxUIFactory();
} else {
// 默认使用跨平台主题或抛出异常
throw new UnsupportedOperationException("不支持的操作系统: " + osName);
}
}
}
// 使用示例
public class AbstractFactoryDemo {
public static void main(String[] args) {
System.out.println("=== 抽象工厂模式演示 ===\n");
// 演示1:手动指定平台
System.out.println("1. Windows平台UI:");
UIFactory windowsFactory = UIFactoryCreator.createFactory(UIFactoryCreator.Platform.WINDOWS);
Application windowsApp = new Application(windowsFactory);
windowsApp.createUI();
windowsApp.renderUI();
windowsApp.simulateUserInteraction();
windowsApp.displayFactoryInfo();
System.out.println("\n2. Mac平台UI:");
UIFactory macFactory = UIFactoryCreator.createFactory(UIFactoryCreator.Platform.MAC);
Application macApp = new Application(macFactory);
macApp.createUI();
macApp.renderUI();
macApp.simulateUserInteraction();
macApp.displayFactoryInfo();
System.out.println("\n3. Linux平台UI:");
UIFactory linuxFactory = UIFactoryCreator.createFactory(UIFactoryCreator.Platform.LINUX);
Application linuxApp = new Application(linuxFactory);
linuxApp.createUI();
linuxApp.renderUI();
linuxApp.simulateUserInteraction();
linuxApp.displayFactoryInfo();
// 演示2:自动检测平台
System.out.println("\n4. 当前平台UI:");
try {
UIFactory currentFactory = UIFactoryCreator.createFactoryForCurrentPlatform();
Application currentApp = new Application(currentFactory);
currentApp.createUI();
currentApp.renderUI();
currentApp.displayFactoryInfo();
} catch (UnsupportedOperationException e) {
System.out.println("自动检测失败: " + e.getMessage());
}
}
}
5. Spring Boot中的实现
java
// 配置类
@Configuration
public class DatabaseConfig {
@Bean
@ConditionalOnProperty(name = "database.type", havingValue = "mysql")
public DatabaseFactory mysqlFactory() {
return new MySQLDatabaseFactory();
}
@Bean
@ConditionalOnProperty(name = "database.type", havingValue = "oracle")
public DatabaseFactory oracleFactory() {
return new OracleDatabaseFactory();
}
@Bean
@ConditionalOnProperty(name = "database.type", havingValue = "postgresql")
public DatabaseFactory postgresqlFactory() {
return new PostgreSQLDatabaseFactory();
}
}
// 数据库抽象产品
public interface Connection {
void connect();
void disconnect();
}
public interface Command {
void execute(String query);
}
public interface Transaction {
void begin();
void commit();
void rollback();
}
// 抽象数据库工厂
public interface DatabaseFactory {
Connection createConnection();
Command createCommand();
Transaction createTransaction();
}
// MySQL实现
@Component
@Slf4j
public class MySQLConnection implements Connection {
@Override
public void connect() {
log.info("MySQL连接已建立");
}
@Override
public void disconnect() {
log.info("MySQL连接已关闭");
}
}
@Component
@Slf4j
public class MySQLCommand implements Command {
@Override
public void execute(String query) {
log.info("执行MySQL查询: {}", query);
}
}
@Component
@Slf4j
public class MySQLTransaction implements Transaction {
@Override
public void begin() {
log.info("MySQL事务开始");
}
@Override
public void commit() {
log.info("MySQL事务提交");
}
@Override
public void rollback() {
log.info("MySQL事务回滚");
}
}
@Component
@Slf4j
public class MySQLDatabaseFactory implements DatabaseFactory {
private final MySQLConnection connection;
private final MySQLCommand command;
private final MySQLTransaction transaction;
@Autowired
public MySQLDatabaseFactory(MySQLConnection connection,
MySQLCommand command,
MySQLTransaction transaction) {
this.connection = connection;
this.command = command;
this.transaction = transaction;
}
@Override
public Connection createConnection() {
return connection;
}
@Override
public Command createCommand() {
return command;
}
@Override
public Transaction createTransaction() {
return transaction;
}
}
// Oracle实现
@Component
@Slf4j
public class OracleConnection implements Connection {
@Override
public void connect() {
log.info("Oracle连接已建立");
}
@Override
public void disconnect() {
log.info("Oracle连接已关闭");
}
}
@Component
@Slf4j
public class OracleCommand implements Command {
@Override
public void execute(String query) {
log.info("执行Oracle查询: {}", query);
}
}
@Component
@Slf4j
public class OracleTransaction implements Transaction {
@Override
public void begin() {
log.info("Oracle事务开始");
}
@Override
public void commit() {
log.info("Oracle事务提交");
}
@Override
public void rollback() {
log.info("Oracle事务回滚");
}
}
@Component
@Slf4j
public class OracleDatabaseFactory implements DatabaseFactory {
private final OracleConnection connection;
private final OracleCommand command;
private final OracleTransaction transaction;
@Autowired
public OracleDatabaseFactory(OracleConnection connection,
OracleCommand command,
OracleTransaction transaction) {
this.connection = connection;
this.command = command;
this.transaction = transaction;
}
@Override
public Connection createConnection() {
return connection;
}
@Override
public Command createCommand() {
return command;
}
@Override
public Transaction createTransaction() {
return transaction;
}
}
// 数据库服务
@Service
@Slf4j
public class DatabaseService {
private final DatabaseFactory databaseFactory;
@Autowired
public DatabaseService(DatabaseFactory databaseFactory) {
this.databaseFactory = databaseFactory;
log.info("数据库服务初始化,使用工厂: {}", databaseFactory.getClass().getSimpleName());
}
@PostConstruct
public void init() {
Connection connection = databaseFactory.createConnection();
connection.connect();
}
public void executeQuery(String query) {
Command command = databaseFactory.createCommand();
command.execute(query);
}
public void executeInTransaction(Runnable operation) {
Transaction transaction = databaseFactory.createTransaction();
try {
transaction.begin();
operation.run();
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw new RuntimeException("事务执行失败", e);
}
}
public String getDatabaseType() {
return databaseFactory.getClass().getSimpleName()
.replace("DatabaseFactory", "")
.toLowerCase();
}
}
// REST控制器
@RestController
@RequestMapping("/api/database")
@Slf4j
public class DatabaseController {
private final DatabaseService databaseService;
public DatabaseController(DatabaseService databaseService) {
this.databaseService = databaseService;
}
@PostMapping("/query")
public ResponseEntity<String> executeQuery(@RequestBody QueryRequest request) {
try {
databaseService.executeQuery(request.getQuery());
return ResponseEntity.ok("查询执行成功");
} catch (Exception e) {
log.error("查询执行失败", e);
return ResponseEntity.status(500).body("查询执行失败: " + e.getMessage());
}
}
@PostMapping("/transaction")
public ResponseEntity<String> executeTransaction() {
try {
databaseService.executeInTransaction(() -> {
// 模拟事务操作
databaseService.executeQuery("INSERT INTO users VALUES ('john')");
databaseService.executeQuery("UPDATE accounts SET balance = 1000");
});
return ResponseEntity.ok("事务执行成功");
} catch (Exception e) {
log.error("事务执行失败", e);
return ResponseEntity.status(500).body("事务执行失败: " + e.getMessage());
}
}
@GetMapping("/info")
public ResponseEntity<DatabaseInfo> getDatabaseInfo() {
DatabaseInfo info = new DatabaseInfo();
info.setType(databaseService.getDatabaseType());
info.setTimestamp(LocalDateTime.now());
return ResponseEntity.ok(info);
}
}
// DTO类
@Data
public class QueryRequest {
private String query;
}
@Data
public class DatabaseInfo {
private String type;
private LocalDateTime timestamp;
}
// 应用配置文件:application.yml
/*
spring:
application:
name: abstract-factory-demo
database:
type: mysql # 可配置为 mysql, oracle, postgresql
*/
6. 抽象工厂模式的变体与进阶用法
6.1 可扩展的抽象工厂
java
// 可扩展的抽象工厂接口
public interface ExtensibleFactory {
<T> T createProduct(Class<T> productType);
void registerProduct(Class<?> productType, Supplier<?> creator);
}
// 实现可扩展工厂
@Slf4j
public class DynamicUIFactory implements ExtensibleFactory {
private final Map<Class<?>, Supplier<?>> creators = new HashMap<>();
public DynamicUIFactory() {
// 注册默认产品创建器
registerProduct(Button.class, WindowsButton::new);
registerProduct(TextBox.class, WindowsTextBox::new);
registerProduct(CheckBox.class, WindowsCheckBox::new);
}
@Override
@SuppressWarnings("unchecked")
public <T> T createProduct(Class<T> productType) {
Supplier<?> creator = creators.get(productType);
if (creator == null) {
throw new IllegalArgumentException("未注册的产品类型: " + productType);
}
return (T) creator.get();
}
@Override
public void registerProduct(Class<?> productType, Supplier<?> creator) {
creators.put(productType, creator);
log.info("注册产品类型: {}", productType.getSimpleName());
}
// 切换产品家族
public void switchToMacFamily() {
registerProduct(Button.class, MacButton::new);
registerProduct(TextBox.class, MacTextBox::new);
registerProduct(CheckBox.class, MacCheckBox::new);
log.info("切换到Mac产品家族");
}
public void switchToLinuxFamily() {
registerProduct(Button.class, LinuxButton::new);
registerProduct(TextBox.class, LinuxTextBox::new);
registerProduct(CheckBox.class, LinuxCheckBox::new);
log.info("切换到Linux产品家族");
}
}
6.2 抽象工厂 + 原型模式
结合原型模式实现产品的快速创建:
java
// 支持原型的抽象工厂
public interface PrototypeFactory extends UIFactory {
Button createButtonPrototype();
TextBox createTextBoxPrototype();
CheckBox createCheckBoxPrototype();
}
// 原型工厂实现
@Slf4j
public class PrototypeUIFactory implements PrototypeFactory {
private final Button buttonPrototype;
private final TextBox textBoxPrototype;
private final CheckBox checkBoxPrototype;
public PrototypeUIFactory(Button buttonPrototype,
TextBox textBoxPrototype,
CheckBox checkBoxPrototype) {
this.buttonPrototype = buttonPrototype;
this.textBoxPrototype = textBoxPrototype;
this.checkBoxPrototype = checkBoxPrototype;
}
@Override
public Button createButton() {
log.debug("通过原型创建按钮");
// 实际中可能需要深拷贝
return buttonPrototype;
}
@Override
public TextBox createTextBox() {
log.debug("通过原型创建文本框");
return textBoxPrototype;
}
@Override
public CheckBox createCheckBox() {
log.debug("通过原型创建复选框");
return checkBoxPrototype;
}
@Override
public Button createButtonPrototype() {
return buttonPrototype;
}
@Override
public TextBox createTextBoxPrototype() {
return textBoxPrototype;
}
@Override
public CheckBox createCheckBoxPrototype() {
return checkBoxPrototype;
}
}
7. 抽象工厂模式 vs 其他模式
7.1 抽象工厂模式 vs 工厂方法模式
- 工厂方法模式:创建单一产品,通过子类决定实例化哪个具体类
- 抽象工厂模式:创建产品家族,通过具体工厂创建一系列相关产品
7.2 抽象工厂模式 vs 建造者模式
- 抽象工厂模式:关注产品家族的创建,产品立即返回
- 建造者模式:关注复杂对象的逐步构建,通过多个步骤创建最终产品
7.3 抽象工厂模式 vs 原型模式
- 抽象工厂模式:通过工厂创建新产品实例
- 原型模式:通过克隆现有实例创建新对象
8. 总结与思考
8.1 抽象工厂模式的优点
- 产品一致性:确保创建的产品属于同一家族,保证兼容性
- 客户端与具体类解耦:客户端只依赖抽象接口,不依赖具体实现
- 易于交换产品家族:通过更换具体工厂即可切换整个产品家族
- 符合开闭原则:新增产品家族无需修改现有代码
8.2 抽象工厂模式的缺点
- 难以支持新种类产品:新增产品种类需要修改所有工厂类
- 类数量爆炸:每个产品家族都需要一套完整的类结构
- 复杂度增加:引入了额外的抽象层,增加了系统复杂度
8.3 深入思考
抽象工厂模式的本质是**"产品家族的封装创建"**。它将相关产品的创建逻辑封装在一起,确保产品之间的兼容性和一致性,让客户端能够以统一的方式使用不同的产品家族。
"抽象工厂模式就像现实世界中的品牌概念。无论是苹果生态系统中的iPhone、Mac、iPad,还是微软生态系统中的Surface、Windows、Office,每个品牌都确保其产品之间的高度兼容性和一致性。这种'家族化'的设计思想,让用户的体验更加连贯和舒适。"
从源码的角度看,抽象工厂模式在Java中有着广泛应用:
- Java AWT Toolkit 的跨平台实现
- Spring Framework 的JdbcTemplate对不同数据库的支持
- 日志框架对多种日志实现的支持
- 消息中间件对不同消息协议的支持
何时使用抽象工厂模式:
- 系统需要独立于其产品的创建、组合和表示时
- 系统需要配置多个产品家族中的一个时
- 需要强调一系列相关产品对象的设计以便进行联合使用时
- 希望提供一个产品类库,只显示它们的接口而不是实现时
使用场景:
- 跨平台UI工具包
- 数据库访问层
- 游戏引擎的资源管理
- 主题系统(浅色/深色主题)
- 不同国家的本地化支持
下一篇预告:设计模式手册023 - 外观模式
版权声明:本文为CSDN博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。