java代码重构
Posted yuzipei1132
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java代码重构相关的知识,希望对你有一定的参考价值。
平时我们写的代码虽然满足了需求但往往不利于项目的开发与维护,以下面的JDBC代码为例
<span style="font-size:18px;">// 增加学生信息
@Override
public void save(Student stu)
String sql = "INSERT INTO t_student(name,age) VALUES(?,?)";
Connection conn = null;
Statement st = null;
try
// 1. 加载注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2. 获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root");
// 3. 创建语句对象
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, stu.getName());
ps.setObject(2, stu.getAge());
// 4. 执行SQL语句
ps.executeUpdate();
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
try
if (st != null)
st.close();
catch (SQLException e)
e.printStackTrace();
finally
try
if (conn != null)
conn.close();
catch (SQLException e)
e.printStackTrace();
// 删除学生信息
@Override
public void delete(Long id)
String sql = "DELETE FROM t_student WHERE id=?";
Connection conn = null;
Statement st = null;
try
// 1. 加载注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2. 获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root");
// 3. 创建语句对象
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, id);
// 4. 执行SQL语句
ps.executeUpdate();
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
try
if (st != null)
st.close();
catch (SQLException e)
e.printStackTrace();
finally
try
if (conn != null)
conn.close();
catch (SQLException e)
e.printStackTrace();
// 修改学生信息
@Override
public void update(Student stu)
String sql = "UPDATE t_student SET name=?,age=? WHERE id=?";
Connection conn = null;
Statement st = null;
try
// 1. 加载注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2. 获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root");
// 3. 创建语句对象
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, stu.getName());
ps.setObject(2, stu.getAge());
ps.setObject(3, stu.getId());
// 4. 执行SQL语句
ps.executeUpdate();
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
try
if (st != null)
st.close();
catch (SQLException e)
e.printStackTrace();
finally
try
if (conn != null)
conn.close();
catch (SQLException e)
e.printStackTrace();
</span>
上述代码中功能没问题,但是代码重复的太多,因此我们可以进行抽取,把重复的代码放到一个工具类JDBCUtil2里
//工具类
public class JDBCUtil2
private JDBCUtil2()
static
// 1. 加载注册驱动
try
Class.forName("com.mysql.jdbc.Driver");
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
public static Connection getConnection()
try
// 2. 获取数据库连接
return DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root");
catch (Exception e)
e.printStackTrace();
return null;
//释放资源
public static void close(ResultSet rs, Statement st, Connection conn)
try
if (rs != null)
rs.close();
catch (SQLException e)
e.printStackTrace();
finally
try
if (st != null)
st.close();
catch (SQLException e)
e.printStackTrace();
finally
try
if (conn != null)
conn.close();
catch (SQLException e)
e.printStackTrace();
在实现类中直接调用工具类中的方法即可
public class StudentDAOImpl2 implements IstudentDAO
// 增加学生信息
@Override
public void save(Student stu)
String sql = "INSERT INTO t_student(name,age) VALUES(?,?)";
Connection conn = null;
PreparedStatement ps=null;
try
conn=JDBCUtil2.getConnection();
// 3. 创建语句对象
ps = conn.prepareStatement(sql);
ps.setObject(1, stu.getName());
ps.setObject(2, stu.getAge());
// 4. 执行SQL语句
ps.executeUpdate();
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil2.close(null, ps, conn);
// 删除学生信息
@Override
public void delete(Long id)
String sql = "DELETE FROM t_student WHERE id=?";
Connection conn = null;
PreparedStatement ps=null;
try
conn=JDBCUtil2.getConnection();
// 3. 创建语句对象
ps = conn.prepareStatement(sql);
ps.setObject(1, id);
// 4. 执行SQL语句
ps.executeUpdate();
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil2.close(null, ps, conn);
// 修改学生信息
@Override
public void update(Student stu)
String sql = "UPDATE t_student SET name=?,age=? WHERE id=?";
Connection conn = null;
PreparedStatement ps=null;
try
conn=JDBCUtil2.getConnection();
// 3. 创建语句对象
ps = conn.prepareStatement(sql);
ps.setObject(1, stu.getName());
ps.setObject(2, stu.getAge());
ps.setObject(3, stu.getId());
// 4. 执行SQL语句
ps.executeUpdate();
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil2.close(null, ps, conn);
@Override
public Student get(Long id)
String sql = "SELECT * FROM t_student WHERE id=?";
Connection conn = null;
Statement st = null;
ResultSet rs = null;
PreparedStatement ps=null;
try
conn=JDBCUtil2.getConnection();
// 3. 创建语句对象
ps = conn.prepareStatement(sql);
ps.setObject(1, id);
// 4. 执行SQL语句
rs = ps.executeQuery();
if (rs.next())
String name = rs.getString("name");
int age = rs.getInt("age");
Student stu = new Student(id, name, age);
return stu;
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil2.close(rs, ps, conn);
return null;
@Override
public List<Student> list()
List<Student> list = new ArrayList<>();
String sql = "SELECT * FROM t_student ";
Connection conn = null;
Statement st = null;
ResultSet rs = null;
PreparedStatement ps=null;
try
conn=JDBCUtil2.getConnection();
// 3. 创建语句对象
ps = conn.prepareStatement(sql);
// 4. 执行SQL语句
rs = ps.executeQuery();
while (rs.next())
long id = rs.getLong("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Student stu = new Student(id, name, age);
list.add(stu);
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil2.close(rs, ps, conn);
return list;
虽然完成了重复代码的抽取,但数据库中的账号密码等直接显示在代码中,不利于后期账户密码改动的维护,我们可以建立个db.propertise文件用来存储这些信息
driverClassName =com.mysql.jdbc.Driver
url =jdbc:mysql:///jdbcdemo
username =root
password =root
只需在工具类中获取里面的信息即可
private static Properties p;
static
// 1. 加载注册驱动
try
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = loader.getResourceAsStream("db.properties");
p = new Properties();
p.load(inputStream);
Class.forName(p.getProperty("driverClassName"));
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
public static Connection getConnection()
try
// 2. 获取数据库连接
return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"),
p.getProperty("password"));
catch (Exception e)
e.printStackTrace();
return null;
抽取到这里貌似已经完成,但在实现类中,依然存在部分重复代码,在DML操作中,除了SQL和设置值的不同,其他都相同,将相同的抽取出去,不同的部分通过参数传递进来,
无法直接放在工具类中,这时我们可以创建一个模板类JDBCTemplate,创建一个DML和DQL的模板来进行对代码的重构。
public class JDBCTemplate
private JDBCTemplate();
//DML通用模板
public static void update(String sql, Object... params)
Connection conn = null;
PreparedStatement ps = null;
try
conn = JDBCUtil2.getConnection();
ps = conn.prepareStatement(sql);
// 设置值
for (int i = 0; i < params.length; i++)
ps.setObject(i + 1, params[i]);
ps.executeUpdate();
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil.close(null, ps, conn);
//DQL同意模板
public static List<Student> query(String sql,Object...params)
List<Student> list=new ArrayList<>();
Connection conn = null;
PreparedStatement ps=null;
ResultSet rs = null;
try
conn=JDBCUtil.getConnection();
ps=conn.prepareStatement(sql);
//设置值
for (int i = 0; i < params.length; i++)
ps.setObject(i+1, params[i]);
rs = ps.executeQuery();
while (rs.next())
long id = rs.getLong("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Student stu = new Student(id, name, age);
list.add(stu);
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil.close(rs, ps, conn);
return list;
实现类直接调用方法即可。
// 增加学生信息
@Override
public void save(Student stu)
String sql = "INSERT INTO t_student(name,age) VALUES(?,?)";
Object[] params=new Object[]stu.getName(),stu.getAge();
JDBCTemplate.update(sql, params);
// 删除学生信息
@Override
public void delete(Long id)
String sql = "DELETE FROM t_student WHERE id=?";
JDBCTemplate.update(sql, id);
// 修改学生信息
@Override
public void update(Student stu)
String sql = "UPDATE t_student SET name=?,age=? WHERE id=?";
Object[] params=new Object[]stu.getName(),stu.getAge(),stu.getId();
JDBCTemplate.update(sql, params);
@Override
public Student get(Long id)
String sql = "SELECT * FROM t_student WHERE id=?";
List<Student> list = JDBCTemplate.query(sql, id);
return list.size()>0? list.get(0):null;
@Override
public List<Student> list()
String sql = "SELECT * FROM t_student ";
return JDBCTemplate.query(sql);
这样重复的代码基本就解决了,但又个很严重的问题就是这个程序DQL操作中只能处理Student类和t_student表的相关数据,无法处理其他类如:Teacher类和t_teacher表。
不同表(不同的对象)
,
不同的表就应该有不同列,不同列处理结果集的代码就应该不一样,处理结果集的操作只有
DAO
自己最清楚,
也就是说,处理结果的方法压根就不应该放在模板方中,应该由每个
DAO
自己来处理。因此我们可以创建一个IResultSetHandle接口来处理结果集
public interface IResultSetHandle
//处理结果集
List handle(ResultSet rs) throws Exception;
DQL模板类中调用IResultSetHandle接口中的handle方法,提醒实现类去自己去实现handle方法
//DQL同意模板
public static List<Student> query(String sql,<span style="color:#ff0000;">IResultSetHandle rsh</span>, Object...params)
List<Student> list=new ArrayList<>();
Connection conn = null;
PreparedStatement ps=null;
ResultSet rs = null;
try
conn=JDBCUtil.getConnection();
ps=conn.prepareStatement(sql);
//设置值
for (int i = 0; i < params.length; i++)
ps.setObject(i+1, params[i]);
rs = ps.executeQuery();
<span style="color:#ff0000;">return rsh.handle(rs);</span>
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil.close(rs, ps, conn);
return list;
实现类自己去实现 IResultSetHandle接口的handle方法,想要处理什么类型数据在里面定义即可
@Override
public Student get(Long id)
String sql = "SELECT * FROM t_student WHERE id=?";
List<Student> list = JDBCTemplate.query(sql,new StudentResultSetHandle(), id);
return list.size()>0? list.get(0):null;
@Override
public List<Student> list()
String sql = "SELECT * FROM t_student ";
return JDBCTemplate.query(sql,new StudentResultSetHandle());
class StudentResultSetHandle implements IResultSetHandle
@Override
public List handle(ResultSet rs) throws Exception
List<Student> list=new ArrayList<>();
while(rs.next())
long id = rs.getLong("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Student stu=new Student(id, name, age);
list.add(stu);
return list;
好了,基本已经大功告成了,但是DQL查询不单单只有查询学生信息(List类型),还可以查询学生数量,这时就要通过泛型来完成
//声明泛型T作为返回类型,谁调用IResultSetHandle,谁就决定T类型
public interface IResultSetHandle<T>
//处理结果集
T handle(ResultSet rs) throws Exception;
//DQL同意模板
public static <T> T query(String sql,IResultSetHandle<T> rsh, Object...params)
Connection conn = null;
PreparedStatement ps=null;
ResultSet rs = null;
try
conn=JDBCUtil.getConnection();
ps=conn.prepareStatement(sql);
//设置值
for (int i = 0; i < params.length; i++)
ps.setObject(i+1, params[i]);
rs = ps.executeQuery();
return rsh.handle(rs);
// 5. 释放资源
catch (Exception e)
e.printStackTrace();
finally
JDBCUtil.close(rs, ps, conn);
return null;
class StudentResultSetHandle implements IResultSetHandle<List<Student>>
public List<Student> handle(ResultSet rs) throws Exception
List<Student> list=new ArrayList<>();
while(rs.next())
long id = rs.getLong("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Student stu=new Student(id, name, age);
list.add(stu);
return list;
这样不仅可以查询List,还可以查询学生数量
// 查询学生整数
@Test
public void testgetTotal() throws Exception
Long totalCount = JDBCTemplate.query("SELECT COUNT(*) tatal FROM t_student", new IResultSetHandle<Long>()
@Override
public Long handle(ResultSet rs) throws Exception
Long totalCount=null;
if(rs.next())
totalCount=rs.getLong("tatal");
return totalCount;
);
System.out.println(totalCount);
好了,重构设计已经完成,好的代码能让我们以后维护更方便,因此学会对代码的重构是很重要的
以上是关于java代码重构的主要内容,如果未能解决你的问题,请参考以下文章