工厂模式,在开发中广泛使用的一种用于对象创建的设计模式,尽管有时候我们可能并不知道自己使用的就是工厂模式或者看到的开源软件源码中用到的就是工厂模式。开源软件中的MyBatis中的SqlSession的创建就是使用了工厂模式,分析如下:
接口 SqlSessionFactory
/**
* Creates an {@link SqlSession} out of a connection or a DataSource
*
* @author Clinton Begin
*/
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
该接口中定义了八个方法用于创建SqlSession, 我们看看默认的实现类(因为MyBatis中该接口的实现类有两个,一个是默认的DefaultSqlSessionFactory,一个是 SqlSessionManager)
/**
* @author Clinton Begin
*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
@Override
public SqlSession openSession(ExecutorType execType) {
return openSessionFromDataSource(execType, null, false);
}
@Override
public SqlSession openSession(TransactionIsolationLevel level) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return openSessionFromDataSource(execType, level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}
@Override
public SqlSession openSession(Connection connection) {
return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
}
@Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return openSessionFromConnection(execType, connection);
}
@Override
public Configuration getConfiguration() {
return configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
private void closeTransaction(Transaction tx) {
if (tx != null) {
try {
tx.close();
} catch (SQLException ignore) {
// Intentionally ignore. Prefer previous error.
}
}
}
}
通过源码可以看出, DefaultSqlSessionFactory实现了SqlSessionFactory的方法,提供了创建SqlSession的实现,那么我们就可以根据不同情况调用相应的方法创建SqlSession了,同时不用关心创建的逻辑,但是当一个对象的创建逻辑非常简单的时候,比如new Object() ,然后是set几个字段值,那么是没有必要使用工厂模式的,如果引入反而会增加系统的复杂。假如只是对象的字段多,那么我们为了创建对象的灵活性可以考虑使用建造者模式,请参考博文*********。
以上所述的工厂模式,是根据不同的参数创建相同的对象,假如同一类对象的创建,我们也可以使用工厂模式,根据类型创建同一类的不同对象。汽车SUV分为大型SUV,中型SUV,紧凑型SUV,小型SUV。那么我们使用工厂模式创建SUV。
SUV接口
public interface SUV {
void running();
}
四种SUV的实现
public class LargeSUV implements SUV {
public void running() {
System.out.println(this.getClass().getSimpleName() + " running...");
}
}
public class MidSUV implements SUV{
public void running() {
System.out.println(this.getClass().getSimpleName() + " running...");
}
}
public class TightSUV implements SUV{
public void running() {
System.out.println(this.getClass().getSimpleName() + " running...");
}
}
public class LittleSUV implements SUV {
public void running() {
System.out.println(this.getClass().getSimpleName() + " running...");
}
}
SUV工厂类
public class SUVFactory {
private SUV suv;
public SUV createSUV(SUVEnum Type){
if (SUVEnum.large == Type) {
suv = new LargeSUV();
}else if (SUVEnum.mid == Type) {
suv = new MidSUV();
}else if (SUVEnum.tight == Type) {
suv = new TightSUV();
}else if (SUVEnum.little == Type) {
suv = new LittleSUV();
}else {
suv = null;
}
return suv ;
}
public static enum SUVEnum{
large,
mid,
tight,
little;
}
}
Demo测试类
public class Demo {
public static void main(String[] args) {
SUVFactory factory = new SUVFactory();
SUV suv = factory.createSUV(SUVFactory.SUVEnum.large);
suv.running();
suv = factory.createSUV(SUVFactory.SUVEnum.mid);
suv.running();
suv = factory.createSUV(SUVFactory.SUVEnum.tight);
suv.running();
suv = factory.createSUV(SUVFactory.SUVEnum.little);
suv.running();
}
}
运行demo结果如下:
LargeSUV running...
MidSUV running...
TightSUV running...
LittleSUV running...
我们根据不同的SUV类型使用工厂模式创建了不同的SUV。
总结:定义一个工厂接口,让所有的子类实现它,在工厂类中定义一个接口变量,在创建产品的方法中传入产品类型,返回对应的实现类即可。
以上是使用工厂模式的两种情况!