设计模式详解-抽象工厂模式
设计模式详解:抽象工厂模式
一、模式概述
抽象工厂模式(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所言:设计模式的价值不在于套用,而在于理解其背后的设计张力,并在恰当的时机做出权衡。