我有一个需要调用方法并返回其值的进程。但是,根据具体情况,此过程可能需要调用几种不同的方法。如果我可以将方法及其参数传递给进程(如在 Python 中),那么这将没有问题。但是,我不知道在 Java 中有任何方法可以做到这一点。
这是一个具体的例子。(此示例使用 Apache ZooKeeper,但您无需了解有关 ZooKeeper 的任何内容即可理解该示例。)
ZooKeeper 对象有几种方法,如果网络出现故障,这些方法将失败。在这种情况下,我总是想重试该方法。为了简化这一点,我创建了一个继承 ZooKeeper 类的“BetterZooKeeper”类,它的所有方法都会在失败时自动重试。
这就是代码的样子:
public class BetterZooKeeper extends ZooKeeper {
private void waitForReconnect() {
// logic
}
@Override
public Stat exists(String path, Watcher watcher) {
while (true) {
try {
return super.exists(path, watcher);
} catch (KeeperException e) {
// We will retry.
}
waitForReconnect();
}
}
@Override
public byte[] getData(String path, boolean watch, Stat stat) {
while (true) {
try {
return super.getData(path, watch, stat);
} catch (KeeperException e) {
// We will retry.
}
waitForReconnect();
}
}
@Override
public void delete(String path, int version) {
while (true) {
try {
super.delete(path, version);
return;
} catch (KeeperException e) {
// We will retry.
}
waitForReconnect();
}
}
}
(在实际程序中,为了简单起见,我从示例中取出了更多的逻辑和方法。)
我们可以看到我使用了相同的重试逻辑,但是每个方法的参数、方法调用和返回类型都不同。
这是我为消除代码重复所做的工作:
public class BetterZooKeeper extends ZooKeeper {
private void waitForReconnect() {
// logic
}
@Override
public Stat exists(final String path, final Watcher watcher) {
return new RetryableZooKeeperAction<Stat>() {
@Override
public Stat action() {
return BetterZooKeeper.super.exists(path, watcher);
}
}.run();
}
@Override
public byte[] getData(final String path, final boolean watch, final Stat stat) {
return new RetryableZooKeeperAction<byte[]>() {
@Override
public byte[] action() {
return BetterZooKeeper.super.getData(path, watch, stat);
}
}.run();
}
@Override
public void delete(final String path, final int version) {
new RetryableZooKeeperAction<Object>() {
@Override
public Object action() {
BetterZooKeeper.super.delete(path, version);
return null;
}
}.run();
return;
}
private abstract class RetryableZooKeeperAction<T> {
public abstract T action();
public final T run() {
while (true) {
try {
return action();
} catch (KeeperException e) {
// We will retry.
}
waitForReconnect();
}
}
}
}
RetryableZooKeeperAction 使用函数的返回类型进行参数化。run() 方法保存重试逻辑,而 action() 方法是需要运行的 ZooKeeper 方法的占位符。BetterZooKeeper 的每个公共方法都实例化了一个匿名内部类,该内部类是 RetryableZooKeeperAction 内部类的子类,并覆盖了 action() 方法。局部变量(很奇怪)隐式传递给 action() 方法,这是可能的,因为它们是最终的。
最后,这种方法确实有效,并且确实消除了重试逻辑的重复。但是,它有两个主要缺点:(1) 每次调用方法时都会创建一个新对象,以及 (2) 丑陋且难以阅读。我还必须解决具有 void 返回值的“删除”方法。
所以,这是我的问题:在 Java 中有没有更好的方法来做到这一点?这不可能是一个完全不常见的任务,其他语言(如 Python)通过允许传递方法使其更容易。我怀疑可能有一种方法可以通过反射来做到这一点,但我一直无法理解它。