模板方法介绍
一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行,形象一点来说,就是已经将步骤定义好了,直接运行就行,换到现实中来,我们有些同学从出生到世界这个摇篮里的时候,爸爸妈妈已经将他的人生规划好了,要上什么学校,上什么课外班,每天的营养搭配,假期去柏林玩还是爱尔兰耍,将来要找什么条件的女朋友,要从事什么工作,都已经安排得明明白白的。
jdbc链接
学过java的同学都知道jdbc,我们刚学Java基础的时候,jdbc是必学的,以前刚学的时候,无论执行一个查询,还是一个更新操作,我想大多同学都会将整个连接过程放在每一个逻辑里面,每个添加,每个查询都写一遍,类似如下:
代码语言:javascript复制public void get() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/system","root","root");
PreparedStatement preparedStatement = connection.prepareStatement("select * from user");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
System.out.println(resultSet.getString("user_id"));
}
connection.close();
preparedStatement.close();
resultSet.close();
}
不难看出,上面的jdbc连接和关闭过程基本是固定的,所以可以抽象为一个模板,这样的话,针对于数据库的CRUD操作就不必写过多的冗余代码,下面使用模板方法模式开始改造。
模板方法模式改造jdbc
1.配置数据源
代码语言:javascript复制public class MyDataSource {
protected DataSource dataSource;
{
com.alibaba.druid.pool.DruidDataSource dataSource = new com.alibaba.druid.pool.DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3307/system");
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
this.dataSource = dataSource;
}
}
2.对于查询,我们编写一个映射结果集的接口RowMapper<T>
代码语言:javascript复制public interface RowMapper<T> {
T mapRow(ResultSet resultSet) throws SQLException;
}
3.编写JdbcTemplate,JdbcTemplate继承了MyDataSource,这样就可以使用数据源了,我们将获取链接,预处理,结果集,关闭连接等单独提取出来,编写了查询和修改方法executeQuery,executeUpdate。
代码语言:javascript复制package template.jdbc;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public abstract class JdbcTemplate extends MyDataSource{
private Connection connection;
private PreparedStatement preparedStatement;
private ResultSet resultSet;
//查询
protected <T> List<T> executeQuery(String sql , RowMapper<T> rowMapper) throws SQLException {
if (sql == null || sql.equals("")) throw new SQLException("sql is null");
preparedStatement = preparedStatement(sql);
resultSet = preparedStatement.executeQuery();
List<T> list = resultSet(resultSet, rowMapper);
close();
return list;
}
//更新
protected int executeUpdate(String sql) throws SQLException {
if (sql == null || sql.equals("")) throw new SQLException("sql is null");
preparedStatement = preparedStatement(sql);
int i = preparedStatement.executeUpdate();
close();
return i;
}
//获取链接
private Connection getConnection() throws SQLException {
return this.dataSource.getConnection();
}
//预执行sql
private PreparedStatement preparedStatement(String sql) throws SQLException {
this.connection = getConnection();
return connection.prepareStatement(sql);
}
//结果集
private <T> List<T> resultSet(ResultSet resultSet , RowMapper<T> rowMapper) throws SQLException {
List<T> list = new ArrayList<>();
while (resultSet.next()){
list.add(rowMapper.mapRow(resultSet));
}
return list;
}
//关闭
private void close() throws SQLException {
if (this.connection != null) this.connection.close();
if (this.preparedStatement != null) this.preparedStatement.close();
if (this.resultSet != null) this.resultSet.close();
}
}
4.编写具体实现类,UserMapper 继承JdbcTemplate
代码语言:javascript复制public class UserMapper extends JdbcTemplate{
//获取人员列表
public List<User> list(String sql) throws SQLException {
return executeQuery(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet) throws SQLException {
return User.builder().userId(resultSet.getString("user_id"))
.uuid(resultSet.getString("uuid"))
.id(resultSet.getLong("id")).build();
}
});
}
}
5.测试查询接口
代码语言:javascript复制public class Client {
public static void main(String[] args) throws SQLException {
String sql = "SELECT * FROM sys_user";
List<User> list = new UserMapper().list(sql);
System.out.println(list);
}
}
结果
[
User(id=1000, uuid=9df9de08354f456c97fae0cdb3df214f, userId=super_admin),
User(id=1002, uuid=26220d63bfd345dabb2f114287965313, userId=mikey),
User(id=1003, uuid=b8c1e673060c437ba0925f119538bdb6, userId=fasf)
]
6.测试更新接口,直接使用JdbcTemplate的executeUpdate方法
代码语言:javascript复制public class Client {
public static void main(String[] args) throws SQLException {
String updateSQL = "UPDATE sys_user SET user_id = "super_admin" WHERE user_id = "admin"";
int update = new UserMapper().executeUpdate(updateSQL);
}
}
上面我们查询的是用户,如果要查询角色,直接编写一个RoleMapper ,然后进行相应的CRUD操作
代码语言:javascript复制public class RoleMapper extends JdbcTemplate{
public List<Role> list(String sql) throws SQLException {
return executeQuery(sql, new RowMapper<Role>() {
@Override
public Role mapRow(ResultSet resultSet) throws SQLException {
return Role.builder().roleName(resultSet.getString("role_name"))
.uuid(resultSet.getString("uuid"))
.id(resultSet.getLong("id")).build();
}
});
}
}
模板方法模式应用场景
存在固定步骤的操作,可以提出公共的部分。
模板方法模式的优点
1.对于有固定步骤的代码,将其封装,有扩展的部分允许自己实现
2.行为由父类控制,子类实现。
模板方法模式的缺点
子类会变得很多,不过去这其实算不上缺点,对于数据库操作,数据表肯定会对应很多实体类,使用ORM框架,自然每一个实体会对应一个Mapper,这是无法避免的。
今天的分享就到这里,感谢你的观看,我们下期见。