工厂模式(二)MyBatis 中展示的简单的工厂模式
在实践中学习才是更古不变的道理,那些最无意义的如玩具般娇小的代码只是为了能够演示基本概念,所以才需要我们去学习开源框架,学习优秀的代码。这次我以MyBatis框架中的DataSource模块作为例子来更深入的探讨工厂模式。
DataSource
DataSource是一个用于获取jdbc连接(Connection)的接口,众所周知,项目中有了Connection对象才能和数据库打交道,而Connection又是如此珍贵的一项资源,所以如何获取Connection成了至关重要的一个环节。每个框架都有自己的一套实现方式,为了让所有的已存在的或者即将产生的实现方式在项目中成为可能,DataSource接口便产生了
此接口定义了两个方法:
这里的DataSource接口在工厂模式里扮演的角色就是Product接口,所有的具体产品类都实现这个接口。MyBatis提供两种实现, 分别是PooledDataSource
和UnpooledDataSource
。
不同的实现类对于如何获取Connection对象,定义了不同的实现方式。比如每次调用UnpooledDataSource.getConnection()
方法都是直接创建一个新的连接;而使用PooledDataSource
则是从连接池中取出已经创建好的空闲的连接
DataSourceFactory
MyBatis同样提供了工厂接口:DataSourceFactory
,针对于上面提到的两个DataSource实现类,MyBatis分别定义了两个工厂实现类UnpooledDataSourceFactory
和PooledDataSourceFactory
不同的工厂实现类负责创建不同类型的DataSource。
UnpooledDataSourceFactory
负责创建UnpooledDataSource
PooledDataSourceFactory
负责创建PooledDataSource
如果需要产生新的DataSource实现,只需要添加对应的工厂实现类,新数据源就可以被MyBatis使用而不必修改已有的代码。符合开放-封闭原则。除此之外工厂方法会向调用者隐藏具体的产品类的实例化细节。
如下图所示,这就是DataSourceFactory工厂方法的典型应用
从这个图片可以看到和我们上节讲的用法完全一致。
MyBatis源码还是比较轻量级,整体上看不是很难理解。本篇主要为了讲工厂模式,所以具体的内部实现细节不展开,感兴趣的读者可以自行查看源码。上面讲的就是工厂模式中最主要的组成部分——被分离出来的变化的部分。那么我们其实还需要看一下MyBatis在哪里使用了这个工厂类,如何使用?以及如何做到在不修改代码的情况下使用新的工厂对象和新的DataSource实现(透明的切换实现方式)
其实这也是大部分web框架实现的基础功能。暴露出扩展点供使用者自定义实现方式或者和第三方框架集成。
到这儿为止,工厂模式就可以结束了。不过此处仍可以做一下延伸。我们可以看看MyBatis框架是如何做的
Mybatis创建DataSourceFactory实例
在MyBatis中,,我们可以通过调用Mapper接口中的方法去执行与之关联的SQL语句。示例代码例如下:
其实在创建SqlSession对象时,MyBatis会根据mybatis-config.xml
配置文件里的配置项去创建DataSourceFactory
实例。具体要创建的是哪个工厂实例是通过配置文件里的参数去指定。比如下面的配置代码片段:
MyBatis在解析配置文件时,会将"POOLED"字符串映射成PooledDataSourceFactory
工厂类,然后创建工厂实例,再通过这个工厂对象获取PooledDataSource
对象,最终将PooledDataSource
对象放入MyBatis的Configuration
对象中。
当第一次创建
SqlSessionFactory
对象时,就会解析mybatis-config.xml
配置文件
Configuration
是MyBatis
初始化过程的核心对象,MyBatis
中几乎全部的配置信息会保存到Configuration
对象中。Configuration
对象是在MyBatis
初始化过程中创建且是全局唯一的, 也有人称它是一个 All-In-One 配置对象
下面看一下具体的代码片段:
在上面说过:第一次创建SqlSessionFactory工厂类时会解析mybatis-config.xml
配置文件。看一下具体代码片段(略去了很多无关代码,具体可以看XMLConfigBuilder.environmentsElement
):
environmentsElement方法调用dataSourceElement方法拿到具体DataSourceFactory。dataSourceElement方法便是解析
元素,然后获取到字符串"POOLED",根据这个值再通过TypeAliasRegistry获取关联的Class对象。
写到这里总体流程基本就走完了。
为了弄明白工厂模式,不得不展示一大堆代码。但是抛开这些代码,单纯对于工厂模式的核心概念来讲,本篇的内容相比于上一篇来讲并没有产生新事物。唯一不同的地方就在于如何在使用工厂对象。
在上篇文章的例子中,都是我们自己手动创建不同的工厂对象然后传递给某些方法,但是作为一个框架来说是不需要手动去做这些事情的。我们唯一要做的就是填写配置文件,然后系统在运行时,自动扫描解析配置文件,根据具体的值生成不同的Class对象,在通过Class创建实际的对象,其中"反射"在此体现出它无比强大的功能和威力。而且也正因为有了多态,才使这一切成为了可能。所以为了创建更加通用性的代码,我们需要面向接口编程或者面向父类编程
以上便是关于简单工厂模式的介绍。其实还有一种我认为更复杂又更高级一点的工厂模式:泛型工厂。
稍后再写吧
版权声明: 本文为 InfoQ 作者【LSJ】的原创文章。
原文链接:【http://xie.infoq.cn/article/ca3905b75bf133a364577f06b】。文章转载请联系作者。
评论