【问题标题】:How to make this code DRYer如何使此代码 DRYer
【发布时间】:2013-11-01 23:44:24
【问题描述】:

所以我有一个生成的类 (PartnerConnection),它为 SalesForce 云平台提供 DML 操作。由于 SalesForce 或运行代码的系统的连接问题,我们遇到了长期运行的集成过程失败的问题。

为了解决这个问题,我扩展了PartnerConnection 类,并命名为AdvancedPartnerConnectionAdvancedPartnerConnection 只是覆盖 PartnerConnection 的方法并用try/catch/retry 逻辑包装它们。

@Override
public QueryResult query(String queryString) throws ConnectionException{
    int attempt = 0;
    ConnectionException lastException = null;
    while(true){
        if(attempt < maxAttempts){ //maxAttempts constant
            if(lastException != null){
                try {
                    //exponentially increase wait times
                    Long sleepTime =(long) Math.pow(sleepBase, attempt) * 300;
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e1) {
                    // something bad has happen, throw the connection exception
                    throw lastException;
                }
            }
            attempt ++;
            try{
                //call super class method
                return super.query(queryString);
            }catch(ConnectionException e){
                lastException = e;
            }
        }else{
            throw lastException;
        }
    }
}

我已经为一些超类方法实现了这一点,唯一的区别是被调用的方法及其参数。如果我决定更改任何重试逻辑,因为我希望它在所有方法中保持一致,那将变得非常痛苦。

有没有人可以将重试逻辑提取到单独的类或方法中,并可能传入函数调用?我在 .NET 中做过类似的事情,但我不确定如何在 java 中做到这一点。

【问题讨论】:

  • PartnerConnection 类的签名?这是你的代码?
  • PartnerConnection 不是我的代码。
  • PartnerConnection 是否实现了任何接口?
  • 不,它只是一个普通的课程。扩展它实际上效果很好,因为我能够将 PartnerConnection 与 AdvancedPartnerConnection 交换,并且不必使用连接更改任何代码

标签: java exception-handling dry


【解决方案1】:

您基本上希望捕获对所有对象方法的所有调用并将一些逻辑应用于所有这些方法。 您可以创建一个Proxy 并在handler 调用方法中重试。

使用这种方法,您可以根据方法签名来决定要做什么。

另一种方法可以使用 AspectJ 或任何其他 AOP 框架,但您的用例很容易添加这种依赖项,IMO。

如果你想添加一些behaviour 的类不是你的,那么这个解决方案可能不是最优雅的。但是,如果您愿意牺牲一些优雅来获得可维护性(因为您没有复制代码),那么您可以:

class NotYourClass {
    public void voidMethod() {}
    public int intMethod(int n) { return 0; }
}

要创建proxy,您必须使用类的所有方法创建interface。这是糟糕的部分,但这不会给您的应用程序添加任何依赖项。

interface YourInterface {
    public void voidMethod();
    public int intMethod(int n);
}

接下来您需要一个包含behaviorInvocationHandler

class YourInvocationHandler implements InvocationHandler {
    private final NotYourClass target;

    public YourInvocationHandler(NotYourClass target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
                // Here you must look to the methods that are the ones that you want.
                return method..invoke(target, args);
        } catch (Exception e) {
            // Retry?
            method.invoke(target, args);
        }
    }
}

请记住,这是我的想法。但应该是这样的。

如果创建该接口对您来说是不可接受的,那么您可以查看一些 AOP 框架。

【讨论】:

  • 如果您有一些额外的时间,您可以添加一个代码示例来说明这是如何工作的吗?
  • 谢谢,但为什么我需要实现“YourInterface”?理想情况下,我只使用调用处理程序来封装重试逻辑,然后在 AdvancedPartnerConnection 中有一个实例,我在每个覆盖中都使用它。创建接口并不是一个真正的选择,因为 PartnerConnection 是在第三方库中生成的代码,最终可能会被更新。
  • 不幸的是我无法使用 InvocationHandler 但 Method.Invoke 原来是有帮助的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
  • 2023-03-20
  • 1970-01-01
  • 2015-05-11
  • 2016-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多