码迷,mamicode.com
首页 > 其他好文 > 详细

[14-03] 示例:利用匿名内部类简化代码

时间:2018-01-20 13:58:27      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:直接   抽象类   抓取   sql   ted   处理异常   分代   如何   数据连接   


内部类的其中一个优势就是可以简化代码,现在以一个常用的JDBC获取数据封装对象的例子,来简单谈谈如何使用匿名内部类来简化代码。

下面这段代码,是用JDBC连接,到数据库查询到数据之后,将数据封装到对象中进行返回,很常见的场景
  1. public List<DepartmentMember> getMemberByDepartmentId(long departmentId) {
  2. List<DepartmentMember> memberList = new ArrayList<DepartmentMember>();
  3. Connection conn = null;
  4. PreparedStatement ps = null;
  5. ResultSet rs = null;
  6. String sql = "SELECT m.id,m.name,m.phone,d.value " +
  7. "FROM t_department_member m LEFT JOIN p_dictionary d ON m.job_id = d.id WHERE m.department_id=?";

  8. try {
  9. conn = DBUtil.getConnection();
  10. ps = conn.prepareStatement(sql);
  11. ps.setLong(1, departmentId);
  12. rs = ps.executeQuery();
  13. while (rs.next()) {
  14. DepartmentMember member = new DepartmentMember();
  15. member.setId(rs.getLong("id"));
  16. member.setName(rs.getString("name"));
  17. member.setPhone(rs.getString("phone"));
  18. member.setJob_name(rs.getString("value"));
  19. memberList.add(member);
  20. }

  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. } finally {
  24. DBUtil.closeConnection(conn, ps, rs);
  25. }

  26. return memberList;
  27. }

可以看到,使用JDBC连接获取数据的话,重复的代码很多(如上图黄色标注的部分),数据连接,获取语句对象,执行查询操作,抓取异常处理,以及关闭连接。这部分代码完全没必要每次都写,想想看,每写一次类似的获取数据的方法,这些代码要copy一次,也是很麻烦的了。

设想一下,我能不能写一个方法,把这些重复的代码写好,每次只需要传入需要变动的那部分就行了。那么问题来了,变动的部分,如果只是sql,那还行,毕竟是String字符串,可以作为形参传入;那我 while(rs.next()) 中的执行代码也想传入,怎么办?Java是不像JS那种可以把函数作为参数的,只能是对象。

没关系,我们先按这个思路试一下,把重复的代码单独写在一个方法中:
  • 为了能让支持其他数据库连接,我们把连接对象作为方法参数传入
  • 为了传入变动代码,我们需要设定一个抽象类作为参数,在方法中执行其方法
  1. public void executeQuery(Connection conn, String sql, SqlExecute action) {
  2. long start = System.currentTimeMillis();
  3. log.debug("execute query start, sql:");
  4. log.debug(sql);
  5. PreparedStatement ps = null;
  6. ResultSet rs = null;
  7. try {
  8. ps = conn.prepareStatement(sql);
  9. //set prepared sql params
  10. action.setParam(ps);
  11. rs = ps.executeQuery();
  12. while (rs.next()) {
  13. //do things while resultset.next()
  14. action.next(rs);
  15. }
  16. } catch (SQLException e) {
  17. e.printStackTrace();
  18. } finally {
  19. DBUtil.closeConnection(conn, ps, rs);
  20. }
  21. long end = System.currentTimeMillis();
  22. log.debug("execute query end, cost time:" + (end - start) + "ms");
  23. }
  1. public abstract class SqlExecute {
  2. /**
  3. * 预编译语句对象赋值
  4. *
  5. * @param ps PreparedStatement预编译语句对象
  6. */
  7. void setParam(PreparedStatement ps) throws SQLException {
  8. //for override
  9. }
  10. /**
  11. * 执行操作
  12. *
  13. * @param rs ResultSet结果集
  14. */
  15. void next(ResultSet rs) throws SQLException {
  16. //for override
  17. }
  18. }

可以看到,由此以来,我只需要调用 executeQuery(Connection conn, String sql, SqlExecute action) 方法,然后需要执行的操作,以SqlExecute的实现类来传入就可以了。但是,每次都为了一个方法,新建一个类来实现SqlExecute,反而显得更繁琐了。幸好,我们有匿名内部类,实际上,我们使用的时候,会变成这样。还是以文章前面的JDBC连接为示例:
  1. public List<DepartmentMember> getMemberByDepartmentId(final long departmentId) {
  2. final List<DepartmentMember> memberList = new ArrayList<DepartmentMember>();
  3. String sql = "SELECT m.id,m.name,m.phone,d.value " +
  4. "FROM t_department_member m LEFT JOIN p_dictionary d ON m.job_id = d.id WHERE m.department_id=?";
  5. executeQuery(DBUtil.getConnection(), sql, new SqlExecute() {
  6. @Override
  7. void setParam(PreparedStatement ps) throws SQLException {
  8. ps.setLong(1, departmentId);
  9. }
  10. @Override
  11. void next(ResultSet rs) throws SQLException {
  12. DepartmentMember member = new DepartmentMember();
  13. member.setId(rs.getLong("id"));
  14. member.setName(rs.getString("name"));
  15. member.setPhone(rs.getString("phone"));
  16. member.setJob_name(rs.getString("value"));
  17. memberList.add(member);
  18. }
  19. });
  20. return memberList;
  21. }

如上方式可以看到,相当于直接把变动的代码作为了参数传入方法。而好处在于,代码变得简洁直观,setParam() 部分就是设置预编译语句对象的值,而next() 就是在对结果集每一行要执行的操作,一目了然,如果后续需要代码变动,在哪里改就可以迅速找到,同时也不需要在此处去特别使用try catch包括代码和处理异常。另外,在executeQuery方法中,顺便还加入了日志打印的方法,因此你也不必再单独每个方法去写一些日志输出的方法了。

最后,值得一提的是,因为内部类的原理,所以这里可以看到,传参的基本数据类型(如departmentId),以及非内部类中的引用数据类型(对象,如memberList),都必须标注为final修饰,这个在内部类的基础知识点钟已经提到,这里就不再过多阐述了。


[14-03] 示例:利用匿名内部类简化代码

标签:直接   抽象类   抓取   sql   ted   处理异常   分代   如何   数据连接   

原文地址:https://www.cnblogs.com/deng-cc/p/8320375.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!