设计模式详解-抽象工厂模式

设计模式详解:抽象工厂模式

一、模式概述

抽象工厂模式(Abstract Factory Pattern)是创建型设计模式的巅峰之作,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。如果说工厂方法模式解决的是"单个产品"的创建问题,那么抽象工厂模式则直面"产品族"的批量创建挑战,在跨平台框架、主题切换系统、多数据库支持等复杂场景中展现出不可替代的价值。

所谓"产品族",是指位于不同产品等级结构中、功能相关联的一组产品。以汽车制造业为例:同一品牌的轿车、SUV、跑车构成产品族,而不同品牌的同类产品则构成产品等级。抽象工厂模式确保客户端始终使用同一产品族中的对象,避免了宝马发动机配奔驰车身的荒谬组合。

二、模式结构

抽象工厂模式包含四个核心角色,形成双层抽象体系:

抽象工厂(Abstract Factory):声明创建抽象产品的方法,每个方法对应一个产品类型。

具体工厂(Concrete Factory):实现抽象工厂接口,负责创建特定产品族的全部对象。

抽象产品(Abstract Product):为每种产品类型声明接口,定义产品规范。

具体产品(Concrete Product):实现抽象产品接口,代表特定产品族中的具体实现。

这种双层结构的核心价值在于:产品族内的对象具有内在一致性约束,抽象工厂作为契约守护者,确保了这一约束不被破坏。

三、深度案例:企业级多数据库访问层

以下展示一个真实场景下的抽象工厂模式应用——支持MySQL与PostgreSQL双数据库的ORM框架设计。

3.1 抽象产品层:数据库组件规范

java
// 连接抽象产品 public interface Connection { void connect(String url); void disconnect(); boolean isAlive(); } // 命令抽象产品 public interface Command { void setSql(String sql); Result execute(); void addParameter(Object param); } // 事务抽象产品 public interface Transaction { void begin(); void commit(); void rollback(); boolean isActive(); } // 结果集抽象产品 public interface Result { boolean next(); Object getValue(String column); int getRowCount(); void close(); }

3.2 具体产品层:MySQL实现族

java
public class MySqlConnection implements Connection { private com.mysql.jdbc.Driver driver; private java.sql.Connection nativeConn; @Override public void connect(String url) { // 加载MySQL驱动,建立原生连接 this.driver = new com.mysql.jdbc.Driver(); this.nativeConn = DriverManager.getConnection(url); // MySQL特有配置:启用批处理重写 nativeConn.setProperty("rewriteBatchedStatements", "true"); } @Override public void disconnect() { if (nativeConn != null) nativeConn.close(); } @Override public boolean isAlive() { return nativeConn != null && nativeConn.isValid(5); } } public class MySqlCommand implements Command { private MySqlConnection connection; private PreparedStatement statement; private List<Object> parameters = new ArrayList<>(); public MySqlCommand(MySqlConnection conn) { this.connection = conn; } @Override public void setSql(String sql) { // MySQL方言转换:LIMIT语法适配 this.statement = connection.nativeConn.prepareStatement( sql.replace("TOP ?", "LIMIT ?") ); } @Override public void addParameter(Object param) { parameters.add(param); } @Override public Result execute() { for (int i = 0; i < parameters.size(); i++) { statement.setObject(i + 1, parameters.get(i)); } return new MySqlResult(statement.executeQuery()); } } public class MySqlTransaction implements Transaction { private MySqlConnection connection; private Savepoint savepoint; @Override public void begin() { connection.nativeConn.setAutoCommit(false); this.savepoint = connection.nativeConn.setSavepoint(); } @Override public void commit() { connection.nativeConn.commit(); connection.nativeConn.setAutoCommit(true); } @Override public void rollback() { if (savepoint != null) { connection.nativeConn.rollback(savepoint); } } @Override public boolean isActive() { return !connection.nativeConn.getAutoCommit(); } }

3.3 具体产品层:PostgreSQL实现族

java
public class PostgreSqlConnection implements Connection { private org.postgresql.Driver driver; private java.sql.Connection nativeConn; @Override public void connect(String url) { this.driver = new org.postgresql.Driver(); this.nativeConn = DriverManager.getConnection(url); // PostgreSQL特有配置:启用扩展查询协议 nativeConn.setProperty("preferQueryMode", "extendedForPrepared"); } @Override public void disconnect() { if (nativeConn != null) nativeConn.close(); } @Override public boolean isAlive() { try { return nativeConn != null && nativeConn.createStatement().execute("SELECT 1"); } catch (SQLException e) { return false; } } } public class PostgreSqlCommand implements Command { private PostgreSqlConnection connection; private PreparedStatement statement; @Override public void setSql(String sql) { // PostgreSQL方言转换:RETURNING子句支持 if (!sql.contains("RETURNING")) { sql += " RETURNING *"; } this.statement = connection.nativeConn.prepareStatement(sql); } @Override public Result execute() { // PostgreSQL支持游标命名,便于服务端分页 statement.setFetchSize(1000); return new PostgreSqlResult(statement.executeQuery()); } } public class PostgreSqlTransaction implements Transaction { private PostgreSqlConnection connection; private String txId; @Override public void begin() { connection.nativeConn.setAutoCommit(false); // PostgreSQL支持事务隔离级别动态调整 connection.nativeConn.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE ); this.txId = UUID.randomUUID().toString(); } @Override public void commit() { connection.nativeConn.commit(); } @Override public void rollback() { connection.nativeConn.rollback(); } @Override public boolean isActive() { // 通过pg_stat_activity查询事务状态 return txId != null; } }

3.4 抽象工厂与具体工厂

java
// 抽象工厂:数据库访问组件工厂 public interface DatabaseFactory { Connection createConnection(); Command createCommand(); Transaction createTransaction(); } // 具体工厂:MySQL组件族 public class MySqlFactory implements DatabaseFactory { @Override public Connection createConnection() { return new MySqlConnection(); } @Override public Command createCommand() { // 确保命令与连接来自同一产品族 return new MySqlCommand((MySqlConnection) createConnection()); } @Override public Transaction createTransaction() { return new MySqlTransaction(); } } // 具体工厂:PostgreSQL组件族 public class PostgreSqlFactory implements DatabaseFactory { @Override public Connection createConnection() { return new PostgreSqlConnection(); } @Override public Command createCommand() { return new PostgreSqlCommand((PostgreSqlConnection) createConnection()); } @Override public Transaction createTransaction() { return new PostgreSqlTransaction(); } }

3.5 客户端与运行时切换

java
public class Repository<T> { private DatabaseFactory factory; private Connection connection; // 通过配置文件或环境变量注入工厂类型 public Repository(String dbType) { this.factory = FactoryProvider.getFactory(dbType); this.connection = factory.createConnection(); this.connection.connect(Config.getConnectionString(dbType)); } public List<T> query(String sql, Object... params) { Command command = factory.createCommand(); command.setSql(sql); for (Object param : params) { command.addParameter(param); } Transaction tx = factory.createTransaction(); try { tx.begin(); Result result = command.execute(); List<T> entities = mapResult(result); tx.commit(); return entities; } catch (Exception e) { tx.rollback(); throw new DataAccessException(e); } } } // 工厂提供者:基于配置动态加载 public class FactoryProvider { private static final Map<String, DatabaseFactory> registry = new HashMap<>(); static { registry.put("mysql", new MySqlFactory()); registry.put("postgresql", new PostgreSqlFactory()); // 扩展点:通过SPI机制加载第三方实现 ServiceLoader.load(DatabaseFactory.class) .forEach(f -> registry.put(f.getName(), f)); } public static DatabaseFactory getFactory(String type) { DatabaseFactory factory = registry.get(type.toLowerCase()); if (factory == null) { throw new UnsupportedDatabaseException(type); } return factory; } }

四、高级主题:产品族的动态扩展

4.1 反射与配置文件解耦

为避免新增产品族时修改工厂提供者,可采用反射机制实现完全解耦:

java
public class ReflectiveFactoryProvider { public static DatabaseFactory getFactory(String className) { try { Class<?> clazz = Class.forName(className); return (DatabaseFactory) clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new FactoryCreationException(className, e); } } }

配合factory.properties配置:

properties
db.factory.mysql=com.example.mysql.MySqlFactory db.factory.postgresql=com.example.postgresql.PostgreSqlFactory db.factory.oracle=com.example.oracle.OracleFactory

4.2 抽象工厂与依赖注入框架的集成

在现代Spring应用中,抽象工厂模式可与FactoryBean接口深度融合:

java
@Component public class DatabaseFactoryBean implements FactoryBean<DatabaseFactory>, ApplicationContextAware { @Value("${database.type:mysql}") private String dbType; private ApplicationContext context; @Override public DatabaseFactory getObject() { // 从Spring容器中获取具体工厂,支持AOP代理 return context.getBean( dbType + "Factory", DatabaseFactory.class ); } @Override public Class<?> getObjectType() { return DatabaseFactory.class; } @Override public boolean isSingleton() { return true; // 工厂本身单例,但产品可配置作用域 } }

五、与其他模式的协作

抽象工厂 + 建造者模式:工厂负责产品族创建,建造者负责复杂对象的逐步组装。例如,数据库连接池的创建由工厂完成,而连接池的参数配置(最大连接数、超时时间等)由建造者处理。

抽象工厂 + 代理模式:工厂创建的产品可自动包装为代理对象。Spring的TransactionProxyFactoryBean即为典型实践,返回的Connection实为事务代理包装。

抽象工厂 + 单例模式:具体工厂本身通常设计为单例,避免重复初始化资源;但产品实例根据需求可为原型或单例。

六、权衡与反思

抽象工厂模式的威力在于产品族一致性约束,代价在于扩展产品等级的困难。当需要新增一种产品类型(如增加Backup备份组件)时,必须修改所有具体工厂及抽象工厂接口,这被称为"抽象工厂的扩展痛点"。

应对此痛点的策略包括:

  • 产品等级稳定预判:在设计初期充分评估产品类型的稳定性,避免频繁变动。
  • 默认方法降级:Java 8+可在抽象工厂中以default方法提供空实现,减少具体工厂的强制修改。
  • 注册表模式演进:将工厂方法提取为独立的策略对象,通过注册表动态组合,弱化抽象工厂的刚性结构。

七、结语

抽象工厂模式是面向对象设计中对"一致性"与"扩展性"双重追求的集中体现。在微服务架构、云原生数据库、多租户SaaS平台等现代场景中,抽象工厂模式依然是构建可移植、可适配系统的核心工具。理解其深层机制,掌握其与其他模式的协作关系,是架构师必备的设计能力。正如GoF所言:设计模式的价值不在于套用,而在于理解其背后的设计张力,并在恰当的时机做出权衡。

返回知识中心