学习目的
》通过学习模板模式,能够在实际业务中完成标准化业务场景
在某些业务场景中,有时候实现一个业务。可能有一些步骤来实现,而每个步骤中会出现不同的场景。此时我们可以那些不变的步骤提取到父类中实现。而那些可变的内容则进行抽象,并通过不同的子类进行完成。
在这里我们利用模板模式完成jdbc的一个标准化业务场景流程
通过一个jdbc操作来实现一个
- 加载驱动类
- 获取连接
- 获取预处理命令
- 执行sql语句,获取结果集
- 解析结果集
- 关闭连接
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.1.152:3306/demo","root","");
//获取预处理命令
PreparedStatement ps = conn.prepareStatement("select * from mms_menu");
//获取结果集
ResultSet resultSet = ps.executeQuery();
//解析结果集
while (resultSet.next()){
Menu menu = new Menu();
menu.setCreatedTime(resultSet.getDate("created_time"));
menu.setId(resultSet.getInt("id"));
menu.setName(resultSet.getString("name"));
menu.setUrl(resultSet.getString("url"));
System.out.println(menu);
}
//关闭连接
resultSet.close();
ps.close();
conn.close();
这是一个很普遍的sql查询,在我们实际的开发中肯定是不会每个命令都这么写一遍的。下面我们通过模板模式来优化这些代码。
对连接管理的工具类
/**
* @Description:
* @Author: gege
* @CreateDate: 2019/3/26 10:30
*/
public class JdbcUtils {
static{
try {
Class.forName("com.mysql.jdbc.Driver");
}catch (Exception e){
System.out.println("找不到驱动类");
}
}
private JdbcUtils (){}
private static Connection conn;
private static PreparedStatement prepareStatement;
//这些参数我们后期往往通过配置文件来配置
private final static String DRIVER_NAME="com.mysql.jdbc.Driver";
private final static String URL="jdbc:mysql://192.168.1.152:3306/demo";
private final static String USER_NAME="root";
private final static String PASS_WORD="";
//获取连接
public static Connection getConnection() throws SQLException {
conn = DriverManager.getConnection("jdbc:mysql://192.168.1.152:3306/demo","root","");
return conn;
}
public static void close(ResultSet rs ,PreparedStatement ps ,Connection conn) throws SQLException{
rs.close();
ps.close();
conn.close();
}
}
通过模板方法将具体的操作实现在父类上,将抽象的步骤定义成一个接口。并有具体的类去实现
/**
* 查询
* @param mapper 要映射结果集实体的实现类
* @param sql sql查询语句
* @param params sql查询参数
* @return sql查询返回的集合
* @throws SQLException
*/
public List<T> executeQuery(IRowMapper<T> mapper,String sql ,Object...params)throws SQLException {
Connection conn =JdbcUtils.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
if(params!=null)
for (int i=0;i<params.length;i++)
ps.setObject(i+1,params[i]);
ResultSet resultSet = ps.executeQuery();
List<T> queryList = new ArrayList<T>();
while (resultSet.next()){
//此处的逻辑是根据不同的实体集来实现的不同业务逻辑,是可变的,我们将其抽象出来。
//等待子类去完成此业务
T entity = mapper.parseEntity(resultSet);
queryList.add(entity);
}
JdbcUtils.close(resultSet,ps,conn);
return queryList;
}
此处是我们定义的接口
public interface IRowMapper<T> {
T parseEntity(ResultSet rs)throws SQLException;
}
下面是我们具体的实现类
public class MenuDao extends JdbcTemplate<Menu>{
public List<Menu> queryByNames(String[] names) throws SQLException {
StringBuffer sql =new StringBuffer("select * from mms_menu where name in (");
for (int i=0;i<names.length;i++) {
sql.append("?");
if(i==names.length-1) sql.append(")");
else sql.append(",");
}
System.out.println(sql.toString());
return super.executeQuery(new IRowMapper<Menu>() {
public Menu parseEntity(ResultSet resultSet) throws SQLException{
Menu menu = new Menu();
menu.setCreatedTime(resultSet.getDate("created_time"));
menu.setId(resultSet.getInt("id"));
menu.setName(resultSet.getString("name"));
menu.setUrl(resultSet.getString("url"));
return menu;
}
},sql.toString(),names);
}
}
测试
String[] names = {"${pageGenerate}","短信平台","接口管理"};
MenuDao menuDao = new MenuDao();
List<Menu> menus = menuDao.queryByNames(names);
for (Menu menu:menus) {
System.out.println(menu);
}
小结:
模板模式的优缺点
优点: 1、利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
2、将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提高代码的扩展性。
3、把不变的行为写在父类上,去除子类的重复代码,提供了一个很好的代码复用平台, 符合开闭原则。
缺点:
1、类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加。
2、类数量的增加,间接地增加了系统实现的复杂度。
3、继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍。 模板方法模式比较简单,相信小伙伴们肯定能学会,也肯定能理解好!只要勤加练习, 多结合业务场景思考问题,就能够把模板方法模式运用好。