0%

工厂模式

一、工厂模式

一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

  • 主要解决:主要解决接口选择的问题。
  • 何时使用:我们明确地计划不同条件下创建不同实例时。

1.1 简单工厂模式

使用静态工厂方法,给过判定传入参数的类型判断创建什么类型的对象,类图如下:

产品抽象:

1
2
3
public interface IProduct {
String getName();
}

具体产品:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ProductA implements IProduct {
@Override
public String getName() {
return "product A";
}
}

public class ProductB implements IProduct {
@Override
public String getName() {
return "product B";
}
}

简单工厂:

1
2
3
4
5
6
7
8
9
10
11
public class SimpleFactory {
public static IProduct getProduct(String type) {
if (type.equals("A")) {
return new ProductA();
} else if (type.equals("B")) {
return new ProductB();
} else {
return null;
}
}
}

使用:

1
2
3
4
5
6
public class TestSimpleFactory {
public static void main(String[] args) {
System.out.println(SimpleFactory.getProduct("A").getName());
System.out.println(SimpleFactory.getProduct("B").getName());
}
}

1.2 工厂方法模式

使静态方法,对不同的产品使用不同的工厂方法创建产品:

工厂方法:

1
2
3
4
5
6
7
8
9
public class MethodFactory {
public static IProduct getProudctA() {
return new ProductA();
}

public static IProduct getProudctB() {
return new ProductB();
}
}

使用:

1
2
3
4
5
6
public class TestMethodFactory {
public static void main(String[] args) {
System.out.println(MethodFactory.getProudctA().getName());
System.out.println(MethodFactory.getProudctB().getName());
}
}

1.3 抽象工厂模式

将产品升级为二维,在产品A B的基础上创建新的特性X Y, 类图:

抽象工厂:

1
2
3
4
5
public interface IAbstractFactory {
IProduct getProductA();

IProduct getProductB();
}

具体工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class FactoryX implements IAbstractFactory{
@Override
public IProduct getProductA() {
return new ProductAX();
}

@Override
public IProduct getProductB() {
return new ProductBX();
}
}

public class FactoryY implements IAbstractFactory{
@Override
public IProduct getProductA() {
return new ProductAY();
}

@Override
public IProduct getProductB() {
return new ProductBY();
}
}

具体产品:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ProductAX extends ProductA {
@Override
public String getName() {
return super.getName() + " X";
}
}

public class ProductAY extends ProductA {
@Override
public String getName() {
return super.getName() + " Y";
}
}

public class ProductBX extends ProductB {
@Override
public String getName() {
return super.getName() + " X";
}
}

public class ProductBY extends ProductB {
@Override
public String getName() {
return super.getName() + " Y";
}
}

使用:

1
2
3
4
5
6
7
8
9
10
11
12
public class TestAbstractFactory {
public static void main(String[] args) {
IAbstractFactory factoryX = new FactoryX();
System.out.println(factoryX.getProductA().getName());
System.out.println(factoryX.getProductB().getName());

IAbstractFactory factoryY = new FactoryY();
System.out.println(factoryY.getProductA().getName());
System.out.println(factoryY.getProductB().getName());

}
}

二、实例分析

2.1 抽象工厂案例

在mybatis中工厂模式随处可见,SqlSessionFactory就是一个典型的抽象工厂的应用,请看下图:

具体工厂类DefaultSqlSessionFactory会产生返回一个DefaultSqlSession,它是一个线程不安全的并且需要手动close的对象,当我们单独使用mybatis的时候会使用该对象,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
//返回具体的SqlSession产品对象
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();
}
}

SqlSessionManager同时继承了SqlSessionFactory和SqlSesion接口,这表示它既是工厂类又是产品类,它作为SqlSession与DefaultSqlSession最大的区别是它内部维护一个线程安全的代理类,并且代理类执行完代理方法会自动调用close方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private class SqlSessionInterceptor implements InvocationHandler {
public SqlSessionInterceptor() {
// Prevent Synthetic Access
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
if (sqlSession != null) {
try {
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {
// 使用java 7提供的try with resource写法,会自动关闭
try (SqlSession autoSqlSession = openSession()) {
try {
final Object result = method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return result;
} catch (Throwable t) {
autoSqlSession.rollback();
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
}
}

线程安全就是通过ThreadLocal在每个线程内部维护一个副本来实现的:

1
2
3
4
5
6
7
8
9
10
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();

public void startManagedSession() {
this.localSqlSession.set(openSession());
}

@Override
public SqlSession openSession() {
return sqlSessionFactory.openSession();
}

2.2 简单工厂案例

在具体工厂类DefaultSqlSessionFactory的openSessionFromConnection方法会创建真正执行sql的Executor对象,该对象的创建就是通过Configuration类的newExecutor方法实现,请看下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
//根据传入的类型可以创建BatchExecutor,ReuseExecutor,SimpleExecutor和CachingExecutor
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}