导语
上一篇文章《Java设计模式之——工厂方法》中对工厂方法进行了一个简单的概述,那么本篇将开始阐述一下抽象工厂方法的概念,以及它在jdk等源码中的使用。
对于抽象工厂而言,它实际上是工厂方法的一个升级版,在有多个业务品种、业务类型时,通过抽象工厂来生产所需要的对象,实际上是一中非常好的解决方式。且工厂方法是为了解决产品等级结构这样一个问题的方法,但是抽象工厂方法解决的是产品族这样一个概念的工厂方法。
一、抽象工厂方法的定义和类型
定义:抽象工厂模式提供一个创建一系列相关或相互依赖的接口,无需指定其他具体的类
类型:创建类型
二、抽象工厂方法的适用场景和优缺点
适用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族),一起使用创建对象需要大量重复的代码
优点:
- 具体产品在应用层代码隔离,无需关心创建细节
- 将一个系列的产品族统一到一起创建
缺点:
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和难度
三、抽象工厂方法UML类图和具体代码实现
1.首先创建同一产品族中的两个抽象产品类
video类:
public abstract class Video {
public abstract void produce();
}
手记类:
public abstract class Notes {
public abstract void produce();
}
2.定义产品具体的实现类
video的实现类:
// JavaVideo 的实现类
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("-----录制Java视频课程-----");
}
}
// PythonVideo 的实现类
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("-----录制Python视频课程-----");
}
}
手记的实现类:
// JavaNotes 的实现类
public class JavaNotes extends Notes {
@Override
public void produce() {
System.out.println("-----编写Java手记-----");
}
}
// PythonNotes 的实现类
public class PythonNotes extends Notes {
@Override
public void produce() {
System.out.println("-----编写Python手记-----");
}
}
3.定义具体产品的工厂类
public class JavaCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
@Override
public Notes getNotes() {
return new JavaNotes();
}
}
public class PythonCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
@Override
public Notes getNotes() {
return new PythonNotes();
}
}
4.测试类
public class MainTest {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Video video = courseFactory.getVideo();
Notes note = courseFactory.getNotes();
video.produce();
note.produce();
}
}
测试结果:
四、抽象工厂方法在JDK源码中的体现
在学习ORM框架时,大多数人都是接触过mybatis这个框架的,那么对于这个框架中含有抽象工厂方法的使用,相信很多人也是知道的。
在mybatis中有这样的一个接口SqlSessionFactory,接口中定义了很多session相关的方法,每个方法传入的相对应的参数都和其具体实现有关系,代码如下:
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();
}
我们可以查看这个接口的具体实现,有SqlSessionManager和DefaultSqlSessionFactory,这里打开DefaultSqlSessionFactory这个实现类,这个类中的实现代码较长,这里就不贴具体代码了,选一个方法进行简单的阐述,代码如下:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
// 具体其他代码省略
@Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return openSessionFromDataSource(execType, level, 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();
}
}
// 其他具体代码省略
}
从上述代码中,可以看到openSession(ExecutorType execType, TransactionIsolationLevel level)这个重载的方法的代码中调用了openSessionFromDataSource(execType, level, false)这个方法,从这个方法的代码中,可以看大具体步骤如下:
- 首先通过configuration获取环境变量
- 再通过环境变量作为参数获取事务的工厂
- 通过环境变量等一些相关参数获取事务
- 通过事务和execType作为参数来新建一个执行器
- 最后通过configuration、executor、autoCommit这些相关参数来得到DefaultSqlSession
最后可以看出,虽然方法上所返回的SqlSession这个对象,但实际上所返回的是DefaultSqlSession这个对象。其实在平常的源码阅读中,可以多注意一些框架的设计原理和思想,这学习的进阶有很大的帮助。