工厂方法模式
介绍
工厂方法模式定义了一个用于创建对象的接口,由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
在工厂方法模式中,创建对象的工作由具体的工厂类来完成,客户端只需要知道所需产品的具体工厂,而无需关心创建细节。
示例
下面是一个简单的工厂方法模式的示例代码:
// 抽象产品类
interface Product {
void use();
}
// 具体产品类 A
class ProductA implements Product {
public void use() {
System.out.println("Product A is used.");
}
}
// 具体产品类 B
class ProductB implements Product {
public void use() {
System.out.println("Product B is used.");
}
}
// 抽象工厂类
interface Factory {
Product createProduct();
}
// 具体工厂类 A
class FactoryA implements Factory {
public Product createProduct() {
return new ProductA();
}
}
// 具体工厂类 B
class FactoryB implements Factory {
public Product createProduct() {
return new ProductB();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Factory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
productA.use();
Factory factoryB = new FactoryB();
Product productB = factoryB.createProduct();
productB.use();
}
}
在上面的代码中,Product
是抽象产品类,它定义了产品对象的通用接口。ProductA
和ProductB
是具体的产品类,它们实现了Product
接口。
Factory
是抽象工厂类,它定义了创建产品的接口。FactoryA
和FactoryB
是具体的工厂类,它们实现了Factory
接口,并提供了创建产品的方法。
在客户端代码中,我们首先创建了两个工厂对象factoryA
和factoryB
,然后分别调用它们的createProduct()
方法来创建对应的产品对象。最后,我们调用产品对象的use()
方法来使用产品。
工厂方法模式使得客户端代码不必关心产品对象的创建细节,只需要知道所需产品的具体工厂即可。和简单工厂模式相比,工厂方法模式可以更方便地扩展新产品,比如,如果我们需要添加一个新的产品类ProductC
,只需要创建一个新的工厂类FactoryC
,并实现createProduct()
方法即可,而不需要修改原有工厂类。
工厂方法模式很好地体现了“对扩展开放,对修改关闭”的设计原则。
在 MyBatis 中的应用
在 MyBatis 中,SqlSessionFactory 和 SqlSession 就是工厂方法模式的应用。SqlSessionFactory 是工厂接口,它定义了创建 SqlSession 的方法。
SqlSessionFactory:
package org.apache.ibatis.session;
import java.sql.Connection;
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:
package org.apache.ibatis.session;
import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.BatchResult;
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
// ...
}
DefaultSqlSessionFactory 实现了 SqlSessionFactory 接口:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
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();
}
}
// ...
}
其实现方法的返回值是 DefaultSqlSession 对象,DefaultSqlSession 实现了 SqlSession 接口:
public class DefaultSqlSession implements SqlSession {
@Override
public <T> T selectOne(String statement) {
return this.<T>selectOne(statement, null);
}
// ...
}
参考:ChatGPT