配色: 字号:
java代码重构
2016-09-07 | 阅:  转:  |  分享 
  
java代码重构

平时我们写的代码虽然满足了需求但往往不利于项目的开发与维护,以下面的JDBC代码为例



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//增加学生信息

@Override

publicvoidsave(Studentstu){

Stringsql="INSERTINTOt_student(name,age)VALUES(?,?)";

Connectionconn=null;

Statementst=null;

try{

//1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2.获取数据库连接

conn=DriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");

//3.创建语句对象

PreparedStatementps=conn.prepareStatement(sql);

ps.setObject(1,stu.getName());

ps.setObject(2,stu.getAge());

//4.执行SQL语句

ps.executeUpdate();

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

try{

if(st!=null)

st.close();

}catch(SQLExceptione){

e.printStackTrace();

}finally{

try{

if(conn!=null)

conn.close();

}catch(SQLExceptione){

e.printStackTrace();

}

}



}



}



//删除学生信息

@Override

publicvoiddelete(Longid){

Stringsql="DELETEFROMt_studentWHEREid=?";

Connectionconn=null;

Statementst=null;

try{

//1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2.获取数据库连接

conn=DriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");

//3.创建语句对象

PreparedStatementps=conn.prepareStatement(sql);

ps.setObject(1,id);

//4.执行SQL语句

ps.executeUpdate();

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

try{

if(st!=null)

st.close();

}catch(SQLExceptione){

e.printStackTrace();

}finally{

try{

if(conn!=null)

conn.close();

}catch(SQLExceptione){

e.printStackTrace();

}

}



}



}



//修改学生信息

@Override

publicvoidupdate(Studentstu){

Stringsql="UPDATEt_studentSETname=?,age=?WHEREid=?";

Connectionconn=null;

Statementst=null;

try{

//1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2.获取数据库连接

conn=DriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");

//3.创建语句对象

PreparedStatementps=conn.prepareStatement(sql);

ps.setObject(1,stu.getName());

ps.setObject(2,stu.getAge());

ps.setObject(3,stu.getId());

//4.执行SQL语句

ps.executeUpdate();

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

try{

if(st!=null)

st.close();

}catch(SQLExceptione){

e.printStackTrace();

}finally{

try{

if(conn!=null)

conn.close();

}catch(SQLExceptione){

e.printStackTrace();

}

}



}

上述代码中功能没问题,但是代码重复的太多,因此我们可以进行抽取,把重复的代码放到一个工具类JDBCUtil2里





[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//工具类

publicclassJDBCUtil2{

privateJDBCUtil2(){

}



static{

//1.加载注册驱动

try{

Class.forName("com.mysql.jdbc.Driver");

}catch(Exceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

}



publicstaticConnectiongetConnection(){

try{

//2.获取数据库连接

returnDriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");

}catch(Exceptione){

e.printStackTrace();

}

returnnull;

}

//释放资源

publicstaticvoidclose(ResultSetrs,Statementst,Connectionconn){

try{

if(rs!=null)

rs.close();

}catch(SQLExceptione){

e.printStackTrace();

}finally{

try{

if(st!=null)

st.close();

}catch(SQLExceptione){

e.printStackTrace();

}finally{

try{

if(conn!=null)

conn.close();

}catch(SQLExceptione){

e.printStackTrace();

}

}

}

}



}

在实现类中直接调用工具类中的方法即可

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicclassStudentDAOImpl2implementsIstudentDAO{



//增加学生信息

@Override

publicvoidsave(Studentstu){

Stringsql="INSERTINTOt_student(name,age)VALUES(?,?)";

Connectionconn=null;

PreparedStatementps=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(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil2.close(null,ps,conn);

}



}



//删除学生信息

@Override

publicvoiddelete(Longid){

Stringsql="DELETEFROMt_studentWHEREid=?";

Connectionconn=null;

PreparedStatementps=null;

try{

conn=JDBCUtil2.getConnection();

//3.创建语句对象

ps=conn.prepareStatement(sql);

ps.setObject(1,id);

//4.执行SQL语句

ps.executeUpdate();

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil2.close(null,ps,conn);

}



}



//修改学生信息

@Override

publicvoidupdate(Studentstu){

Stringsql="UPDATEt_studentSETname=?,age=?WHEREid=?";

Connectionconn=null;

PreparedStatementps=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(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil2.close(null,ps,conn);

}



}



@Override

publicStudentget(Longid){

Stringsql="SELECTFROMt_studentWHEREid=?";

Connectionconn=null;

Statementst=null;

ResultSetrs=null;

PreparedStatementps=null;

try{

conn=JDBCUtil2.getConnection();

//3.创建语句对象

ps=conn.prepareStatement(sql);

ps.setObject(1,id);

//4.执行SQL语句

rs=ps.executeQuery();

if(rs.next()){

Stringname=rs.getString("name");

intage=rs.getInt("age");

Studentstu=newStudent(id,name,age);

returnstu;

}

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil2.close(rs,ps,conn);

}

returnnull;

}



@Override

publicListlist(){

Listlist=newArrayList<>();

Stringsql="SELECTFROMt_student";

Connectionconn=null;

Statementst=null;

ResultSetrs=null;

PreparedStatementps=null;

try{

conn=JDBCUtil2.getConnection();

//3.创建语句对象

ps=conn.prepareStatement(sql);

//4.执行SQL语句

rs=ps.executeQuery();

while(rs.next()){

longid=rs.getLong("id");

Stringname=rs.getString("name");

intage=rs.getInt("age");

Studentstu=newStudent(id,name,age);

list.add(stu);

}

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil2.close(rs,ps,conn);

}

returnlist;

}

}

虽然完成了重复代码的抽取,但数据库中的账号密码等直接显示在代码中,不利于后期账户密码改动的维护,我们可以建立个db.propertise文件用来存储这些信息



[html]viewplaincopy在CODE上查看代码片派生到我的代码片

driverClassName=com.mysql.jdbc.Driver

url=jdbc:mysql:///jdbcdemo

username=root

password=root

只需在工具类中获取里面的信息即可



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

privatestaticPropertiesp;

static{

//1.加载注册驱动

try{

ClassLoaderloader=Thread.currentThread().getContextClassLoader();

InputStreaminputStream=loader.getResourceAsStream("db.properties");

p=newProperties();

p.load(inputStwww.shanxiwang.netream);

Class.forName(p.getProperty("driverClassName"));

}catch(Exceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

}



publicstaticConnectiongetConnection(){

try{

//2.获取数据库连接

returnDriverManager.getConnection(p.getProperty("url"),p.getProperty("username"),

p.getProperty("password"));

}catch(Exceptione){

e.printStackTrace();

}

returnnull;

}

抽取到这里貌似已经完成,但在实现类中,依然存在部分重复代码,在DML操作中,除了SQL和设置值的不同,其他都相同,将相同的抽取出去,不同的部分通过参数传递进来,无法直接放在工具类中,这时我们可以创建一个模板类JDBCTemplate,创建一个DML和DQL的模板来进行对代码的重构。



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicclassJDBCTemplate{

privateJDBCTemplate(){};

//DML通用模板

publicstaticvoidupdate(Stringsql,Object...params){

Connectionconn=null;

PreparedStatementps=null;

try{

conn=JDBCUtil2.getConnection();

ps=conn.prepareStatement(sql);

//设置值

for(inti=0;i
ps.setObject(i+1,params[i]);

}

ps.executeUpdate();

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil.close(null,ps,conn);

}

}

//DQL同意模板

publicstaticListquery(Stringsql,Object...params){

Listlist=newArrayList<>();

Connectionconn=null;

PreparedStatementps=null;

ResultSetrs=null;

try{

conn=JDBCUtil.getConnection();

ps=conn.prepareStatement(sql);

//设置值

for(inti=0;i
ps.setObject(i+1,params[i]);

}

rs=ps.executeQuery();

while(rs.next()){

longid=rs.getLong("id");

Stringname=rs.getString("name");

intage=rs.getInt("age");

Studentstu=newStudent(id,name,age);

list.add(stu);

}

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil.close(rs,ps,conn);

}

returnlist;

}

}

实现类直接调用方法即可。

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//增加学生信息

@Override

publicvoidsave(Studentstu){

Stringsql="INSERTINTOt_student(name,age)VALUES(?,?)";

Object[]params=newObject[]{stu.getName(),stu.getAge()};

JDBCTemplate.update(sql,params);

}



//删除学生信息

@Override

publicvoiddelete(Longid){

Stringsql="DELETEFROMt_studentWHEREid=?";

JDBCTemplate.update(sql,id);

}



//修改学生信息

@Override

publicvoidupdate(Studentstu){

Stringsql="UPDATEt_studentSETname=?,age=?WHEREid=?";

Object[]params=newObject[]{stu.getName(),stu.getAge(),stu.getId()};

JDBCTemplate.update(sql,params);

}



@Override

publicStudentget(Longid){

Stringsql="SELECTFROMt_studentWHEREid=?";

Listlist=JDBCTemplate.query(sql,id);

returnlist.size()>0?list.get(0):null;

}



@Override

publicListlist(){

Stringsql="SELECTFROMt_student";

returnJDBCTemplate.query(sql);

}

这样重复的代码基本就解决了,但又个很严重的问题就是这个程序DQL操作中只能处理Student类和t_student表的相关数据,无法处理其他类如:Teacher类和t_teacher表。不同表(不同的对象),不同的表就应该有不同列,不同列处理结果集的代码就应该不一样,处理结果集的操作只有DAO自己最清楚,也就是说,处理结果的方法压根就不应该放在模板方中,应该由每个DAO自己来处理。因此我们可以创建一个IResultSetHandle接口来处理结果集



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicinterfaceIResultSetHandle{

//处理结果集

Listhandle(ResultSetrs)throwsException;

}

DQL模板类中调用IResultSetHandle接口中的handle方法,提醒实现类去自己去实现handle方法





[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//DQL同意模板

publicstaticListquery(Stringsql,IResultSetHandlersh,Object...params){

Listlist=newArrayList<>();

Connectionconn=null;

PreparedStatementps=null;

ResultSetrs=null;

try{

conn=JDBCUtil.getConnection();

ps=conn.prepareStatement(sql);

//设置值

for(inti=0;i
ps.setObject(i+1,params[i]);

}

rs=ps.executeQuery();

returnrsh.handle(rs);

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil.close(rs,ps,conn);

}

returnlist;

}





实现类自己去实现IResultSetHandle接口的handle方法,想要处理什么类型数据在里面定义即可

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

@Override

publicStudentget(Longid){

Stringsql="SELECTFROMt_studentWHEREid=?";

Listlist=JDBCTemplate.query(sql,newStudentResultSetHandle(),id);

returnlist.size()>0?list.get(0):null;

}



@Override

publicListlist(){

Stringsql="SELECTFROMt_student";

returnJDBCTemplate.query(sql,newStudentResultSetHandle());

}



classStudentResultSetHandleimplementsIResultSetHandle{



@Override

publicListhandle(ResultSetrs)throwsException{

Listlist=newArrayList<>();

while(rs.next()){

longid=rs.getLong("id");

Stringname=rs.getString("name");

intage=rs.getInt("age");

Studentstu=newStudent(id,name,age);

list.add(stu);

}

returnlist;

}



}



好了,基本已经大功告成了,但是DQL查询不单单只有查询学生信息(List类型),还可以查询学生数量,这时就要通过泛型来完成

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//声明泛型T作为返回类型,谁调用IResultSetHandle,谁就决定T类型

publicinterfaceIResultSetHandle{

//处理结果集

Thandle(ResultSetrs)throwsException;

}



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//DQL同意模板

publicstaticTquery(Stringsql,IResultSetHandlersh,Object...params){

Connectionconn=null;

PreparedStatementps=null;

ResultSetrs=null;

try{

conn=JDBCUtil.getConnection();

ps=conn.prepareStatement(sql);

//设置值

for(inti=0;i
ps.setObject(i+1,params[i]);

}

rs=ps.executeQuery();

returnrsh.handle(rs);

//5.释放资源

}catch(Exceptione){

e.printStackTrace();

}finally{

JDBCUtil.close(rs,ps,conn);

}

returnnull;

}



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

classStudentResultSetHandleimplementsIResultSetHandle>{



publicListhandle(ResultSetrs)throwsException{

Listlist=newArrayList<>();

while(rs.next()){

longid=rs.getLong("id");

Stringname=rs.getString("name");

intage=rs.getInt("age");

Studentstu=newStudent(id,name,age);

list.add(stu);

}

returnlist;

}



这样不仅可以查询List,还可以查询学生数量



[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//查询学生整数

@Test

publicvoidtestgetTotal()throwsException{

LongtotalCount=JDBCTemplate.query("SELECTCOUNT()tatalFROMt_student",newIResultSetHandle(){



@Override

publicLonghandle(ResultSetrs)throwsException{

LongtotalCount=null;

if(rs.next()){

totalCount=rs.getLong("tatal");

}

returntotalCount;

}

});

System.out.println(totalCount);

}

好了,重构设计已经完成,好的代码能让我们以后维护更方便,因此学会对代码的重构是很重要的

献花(0)
+1
(本文系网络学习天...首藏)