您的位置:首页 > 其它

重构示例_01

2015-12-21 21:53 435 查看
遇到这样的代码:
public void callMethodA() {
List<TomcatVO> list = tomcatDao.getTomcat();
for (final TomcatVO tomcat : list) {
executor.execute(new Runnable() {
public void run() {
IndexService indexService = (IndexService) getRmiObject(
tomcat.getUrl(), IndexService.class);
for (int i = 0; i < RETRYTIME; i++) {
try {
indexService.getXXX();
break;
} catch (RemoteException e) {
if (RETRYTIME - 1 == i) {
System.out.println("callMethodA : " + e);
}
} catch (Exception e) {
System.out.println("callMethodA : " + e);
break;
}
}
}
});
}
}

public void callMethodB() {
List<TomcatVO> list = tomcatDao.getTomcat();
for (final TomcatVO tomcat : list) {
executor.execute(new Runnable() {
public void run() {
IndexService indexService = (IndexService) getRmiObject(
tomcat.getUrl(), IndexService.class);
for (int i = 0; i < RETRYTIME; i++) {
try {
indexService.getYYY();
break;
} catch (RemoteException e) {
if (RETRYTIME - 1 == i) {
System.out.println("callMethodB : " + e);
}
} catch (Exception e) {
System.out.println("callMethodB : " + e);
break;
}
}
}
});
}
}
代码流程很简单,就是查询数据库表,获取各个RMI服务器的URL,然后生成对应的rmi代理对象,调用相应的方法,如果是RemoteExceptio失败则重试二次,是Exception失败则不再重试。但是感觉代码有点冗余,每次都需要码上查询数据库、new Runnable等代码,于是尝试重构一把:
public void callMethodA() {
callRPC(new RMITask() {
@Override
void work() {
for (int i = 0; i < RETRYTIME; i++) {
try {
getIndexService().getXXX();
break;
} catch (RemoteException e) {
if (RETRYTIME - 1 == i) {
System.out.println("callMethodB : " + e);
}
} catch (Exception e) {
System.out.println("callMethodB : " + e);
break;
}
}
}
});
}

private abstract class RMITask {
private IndexService indexService;

public IndexService getIndexService() {
return indexService;
}

public void setIndexService(IndexService indexService) {
this.indexService = indexService;
}

abstract void work();
}

private void callRPC(final RMITask task) {
List<TomcatVO> list = tomcatDao.getTomcat();
for (final TomcatVO tomcat : list) {
executor.execute(new Runnable() {
public void run() {
IndexService indexService = (IndexService) getRmiObject(
tomcat.getUrl(), IndexService.class);
task.setIndexService(indexService);
task.work();
}
});
}
}
这里,先创建一个抽象类RMITask,期望具体的方法在work()块中实现。于是有了这样的设计:callMethodA()中不再直接写繁杂的代码,而是调用callRPC ()方法,该方法可以做数据库查询和new Runnable()的事情,callRPC ()会去调用其传入的RMITask参数的work ()方法,而在work ()方法的具体处理逻辑则在callMethodA()中体现。

      然而,依然存在一个问题,callRPC ()传入的task会被多线程共享,task.setIndexService()可能会导致整个RMI调用中并不是每个rmi代理对象如期望的那样去调用对应的rmi方法。举例说明一下,线程A根据urlA获得的rmi代理对象是indexServiceA,并set到task中,然后CPU切换到线程B执行,线程B根据urlB获得的rmi代理对象是indexServiceB,并set到task中,之后线程A开始执行task.work(),此时该任务去调用的是indexServiceB的rmi方法,线程B调用的也将是indexServiceB的任务。于是indexServiceB的rmi方法会调用两次,而indexServiceA的rmi方法不会被调用。

      如何解决?想到了clone()方式,于是做了如下改进:
private abstract class RMITask implements Cloneable {
private IndexService indexService;

public IndexService getIndexService() {
return indexService;
}

public void setIndexService(IndexService indexService) {
this.indexService = indexService;
}

abstract void work();

@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

private void callRPC(final RMITask task) {
List<TomcatVO> list = tomcatDao.getTomcat();
for (final TomcatVO tomcat : list) {
executor.execute(new Runnable() {
public void run() {
IndexService indexService = (IndexService) getRmiObject(
tomcat.getUrl(), IndexService.class);
RMITask realTask = null;
try {
realTask = (RMITask) task.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
realTask.setIndexService(indexService);
realTask.work();
}
});
}
}

也许会有疑问,这里简单的clone()实现只是一个浅拷贝,不过没关系拷贝前indexService是为null的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: