定义
大话设计模式-中介者模式(Mediator):
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
上面是正式的术语描述,其实就是一个媒介的作用,比如卖房的中介,联合国理事会等都是这样一个作用,在日常生活中很常见。
下面使用 ORM 框架 MyBatis 来学习下这个模式,但是更多的是一个 MyBatis 的源码入门学习。
案例
原始实现
- 手动与数据库交互,需要指定是什么数据库
- 处理返回数据比较麻烦,需要自己手动一个个获取
- 除了真正实现业务的 SQL ,其他都是我们不关系的。而真正 SQL 只占了一行代码。
public class JdbcUtil {
private static Logger logger = LoggerFactory.getLogger(JdbcUtil.class);
private static String url = "jdbc:mysql://localhost:3306/apimgt_db_test";
private static String username = "root";
private static String password = "root";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取数据库连接
Connection connection = DriverManager.getConnection(url, username, password);
//3.操作数据库
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from access_api_log limit 1");
while (resultSet.next()) {
logger.info("获取主键值,{}", resultSet.getLong("id"));
}
}
}
中介者模式
- 实现对数据库连接的封装
- 实现对返回数据的封装
可以说这是对 MyBatis 的超级简化版代码。
解析 xml 配置文件
我们这里使用的 dom4j jar 包。现在MyBatis 使用的解析 MXL 文件都是 java 自带的 org.w3c.dom 工具包,以及自己衍生的一些类函数。
// mybatis-config-datasource.xml
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="DRUID">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/apimgt_db_test?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/User_Mapper.xml"/>
</mappers>
</configuration>
// Mapper.xml 文件
<mapper namespace="com.practice.mybatislearn.dao.IUserDao">
<select id="queryUserInfoById" parameterType="java.lang.Long" >
SELECT *
FROM access_api_log
limit 1
</select>
</mapper>
解析方法执行语句
- 一个方法解析 xml 配置文件获得数据库连接。
- 一个方法解析 mapper 文件获取 SQL 语句
- 最终结合起来执行并返回封装结果封装
public ResultSet parse() {
try {
//环境,连接数据库
Connection connection = environmentsElement(root.element("environments"));
//解析映射器,获取 sql 语句
String sql = mapperElement(root.element("mappers"));
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
return resultSet;
} catch (Exception e) {
throw new RuntimeException("Error parsing SQL Mapper Configuration. Cause:" + e, e);
}
}
封装结果
这里是对结果的简单封装,就只是封装为了一个 Map 。真正的 MyBatis 功能非常丰富,可以映射为 Bean 等
static Map resultSet2Obj(ResultSet resultSet) {
Map map = new HashMap();
try {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
//每次遍历行值
while (resultSet.next()) {
for (int i = 1; i < columnCount; i++) {
Object value = resultSet.getObject(i);
String columnName = metaData.getColumnName(i);
map.put(columnName, value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
调用
我们只需要配置好我们的配置接口,然后 XMLBuilder 类:
- 解析配置类获取数据库连接
- 获取 sql 语句
- 执行语句返回结果
public class ApiTest {
public static void main(String[] args) throws SQLException {
XMLBuilder xmlBuilder = new XMLBuilder();
ResultSet resultSet = xmlBuilder.parse();
Map result = ResultObject.resultSet2Obj(resultSet);
System.out.println("结果为:"+result);
}
}
- 我们最后在对结果进行封装,返回到我们想要的格式,而不是我们自己手动的去解析 ResultSet 结果集。
总结
- 上面的超级简化的 ORM 框架对数据库连接、SQL 执行、结果返回都进行了封装,我们只需要配置好信息即可。
- 虽然上面的看起来更像是两个函数的拼接,但是大概思路是这样的。这种设计模式满足单一职责、开闭原则,内部实现对客户端隐藏。外部人员只需要调用即可
具体代码可参考:gitee.com/ncharming/k…