什么是抽象工厂模式
抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体类。该模式属于创建型设计模式。。抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂中的具体工厂不只是创建一个产品,而是创建一组产品。
在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于生产多种不同的产品,这些产品组成一个产品组。
在工厂方法模式中具体工厂只负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性。一般情况下,一个具体工厂只有一个或一组重载的工厂方法。
抽象工厂模式包含一下几个角色:
AbstractFactory(抽象工厂):声明了一组用于创建一组产品的方法,每一个方法对应一种产品。
ConcreteFactory(具体工厂):实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品组。
AbstractProduct(抽象产品):为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
ConcreteProduct(具体产品):定义了具体工厂生产的具体产品的对象,实现抽象产品接口中声明的业务方法。
在抽象工厂中声明多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或具体类(可能有很多初学者认为抽象工厂模式就是定义抽象类,其实不然,这是一个误区!)
具体工厂实现了抽象工厂,每一个具体的工厂方法可以返回一个特定的产品对象,而同一个具体工厂所创建的产品对象构成了产品组。
抽象工厂模式的优缺点
优点
- 抽象工厂模式隔离了具体类的生成,我们可以很容易的切换一个具体工厂。
- 当一个产品组中的多个对象设计到一起时,能够保证同时只能使用同一个产品组中的一个对象。
- 新增产品组很方便,符合开闭原则。
缺点
-
增加新的产品等级结构比较麻烦,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加新的产品方法,不符合开闭原则。
-
抽象工厂模式的应用场景
-
一个系统不应该依赖于产品类如何被创建,组合和表达的细节
-
系统中有多个产品组,而每次只使用其中一个
抽象工厂模式案例
/**
* 创建蔚小理的抽象工厂,分SUV和轿车
*/
public abstract class AbstractCardFactory {
// 买SUV
public abstract SUV orderSUV();
// 买轿车
public abstract LittleCar orderLittleCar();
}
--------------------------------------------------------------------------------
/**
* 蔚来车具体工厂
*/
public class NIOCarFactory extends AbstractCardFactory {
@Override
public SUV orderSUV() {
return new NIOSUV();
}
@Override
public LittleCar orderLittleCar() {
return new NIOLittleCar();
}
}
/**
* 理想车具体工厂
*/
public class ONECarFactory extends AbstractCardFactory {
@Override
public SUV orderSUV() {
return new ONESUV();
}
@Override
public LittleCar orderLittleCar() {
return new ONELittleCar();
}
}
/**
* 小鹏车具体工厂
*/
public class XPCarFactory extends AbstractCardFactory {
@Override
public SUV orderSUV() {
return new XPSUV();
}
@Override
public LittleCar orderLittleCar() {
return new XPLittleCar();
}
}
--------------------------------------------------------------------------------
/**
* 轿车抽象产品
*/
public interface LittleCar {
void buy();
}
/**
* SUV 抽象产品
*/
public interface SUV {
void buy();
}
--------------------------------------------------------------------------------
/**
* 蔚来轿车具体产品
*/
public class NIOLittleCar implements LittleCar {
@Override
public void buy() {
System.out.println("购买蔚来轿车");
}
}
/**
* 理想轿车具体产品
*/
public class ONELittleCar implements LittleCar {
@Override
public void buy() {
System.out.println("购买理想轿车");
}
}
/**
* 小鹏轿车具体产品
*/
public class XPLittleCar implements LittleCar {
@Override
public void buy() {
System.out.println("购买小鹏轿车");
}
}
/**
* 蔚来SUV具体产品
*/
public class NIOSUV implements SUV {
@Override
public void buy() {
System.out.println("购买蔚来SUV");
}
}
/**
* 理想SUV具体产品
*/
public class ONESUV implements SUV {
@Override
public void buy() {
System.out.println("购买理想SUV");
}
}
/**
* 小鹏SUV具体产品
*/
public class XPSUV implements SUV {
@Override
public void buy() {
System.out.println("购买小鹏SUV");
}
}
--------------------------------------------------------------------------------
public class Test {
public static void main(String[] args) {
// 选择理想
ONECarFactory oneCarFactory = new ONECarFactory();
// 购买理想SUV
oneCarFactory.orderSUV().buy();
// 选择蔚来
NIOCarFactory nioCarFactory = new NIOCarFactory();
// 购买蔚来SUV
nioCarFactory.orderSUV().buy();
}
}
抽象工厂在源码中的应用
JDBC
// Connection 接口是一个经典的抽象工厂
// Statement、PreparedState、CallableStatement 就是 Connection 这个抽象工厂中提供的三个抽象产品
// 抽象工厂
public interface Connection extends Wrapper, AutoCloseable {
// 创建sql的执行对象
Statement createStatement() throws SQLException;
// 创建支持预编译的sql执行对象
PreparedStatement prepareStatement(String sql) throws SQLException;
// 创建支持存储过程的sql执行对象
CallableStatement prepareCall(String sql) throws SQLException;
}
// 具体工厂
public class ConnectionImpl implements JdbcConnection, SessionEventListener, Serializable {
@Override
public java.sql.Statement createStatement() throws SQLException {
return createStatement(DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY);
}
@Override
public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException {
return prepareStatement(sql, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY);
}
@Override
public java.sql.CallableStatement prepareCall(String sql) throws SQLException {
return prepareCall(sql, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY);
}
}
// 抽象产品
public interface Statement extends Wrapper, AutoCloseable {
// 执行查询方法
ResultSet executeQuery(String sql) throws SQLException;
// 执行更新方法
int executeUpdate(String sql) throws SQLException;
}
public interface PreparedStatement extends Statement {
// 执行查询方法
ResultSet executeQuery() throws SQLException;
// 执行更新方法
int executeUpdate() throws SQLException;
}
public interface CallableStatement extends PreparedStatement {
// 注册存储过程出参
void registerOutParameter(int parameterIndex, int sqlType) throws SQLException;
}
// 具体工厂
public class StatementImpl implements JdbcStatement {
@Override
public java.sql.ResultSet executeQuery(String sql) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
JdbcConnection locallyScopedConn = this.connection;
this.retrieveGeneratedKeys = false;
checkNullOrEmptyQuery(sql);
resetCancelledState();
implicitlyCloseAllOpenResults();
......
return this.results;
}
}
......
}
public class ClientPreparedStatement extends com.mysql.cj.jdbc.StatementImpl implements JdbcPreparedStatement {
@Override
public java.sql.ResultSet executeQuery() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
JdbcConnection locallyScopedConn = this.connection;
checkForDml(((PreparedQuery<?>) this.query).getOriginalSql(), ((PreparedQuery<?>) this.query).getParseInfo().getFirstStmtChar());
this.batchedGeneratedKeys = null;
resetCancelledState();
implicitlyCloseAllOpenResults();
clearWarnings();
......
return this.results;
}
}
......
}
public class CallableStatement extends ClientPreparedStatement implements java.sql.CallableStatement {
@Override
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
try {
MysqlType mt = MysqlType.getByJdbcType(sqlType);
registerOutParameter(parameterIndex, mt);
} catch (FeatureNotAvailableException nae) {
throw SQLError.createSQLFeatureNotSupportedException(Messages.getString("Statement.UnsupportedSQLType") + JDBCType.valueOf(sqlType),
MysqlErrorNumbers.SQL_STATE_DRIVER_NOT_CAPABLE, getExceptionInterceptor());
}
}
......
}