重构示例_01

设计模式 专栏收录该内容
15 篇文章 0 订阅
遇到这样的代码:
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的。





  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值