如何安全地装饰现有的回调?
假设我使用以下回调API:
Suppose I'm working with the following callback API:
/**
* Registers a new action which will be run at some later time on
* some other thread, clearing any previously set callback action.
*
* @param callback an action to be run later.
* @returns the previously registered action.
*/
public Runnable register(Runnable callback);
我想注册我自己的操作,但是我想保留任何设置的行为。换句话说,我想我的动作看起来像:
I'd like to register my own action, but I want to preserve any set behavior. In other words I'd like my action to look something like:
new Runnable() {
public void run() {
// do my work
originalCallback.run();
}
}
最简单的方法是提供 originalCallback $ c> to my
Runnable
?
What's the cleanest way to provide originalCallback
to my Runnable
?
当调用回调或涉及一些复杂的锁定时, originalCallback
不可用。
The naive solutions that come to mind risk introducing a window of time where originalCallback
isn't available when the callback is called, or that involve some intricate locking.
经过一番挖掘,我找到了Guava的 SettableFuture
和Java 8的 CompletableFuture
。我将把 BlockingSupplier
留给后代,但是这些 Future
的实现将更加标准化,
After some more digging I found Guava's SettableFuture
and Java 8's CompletableFuture
. I'll leave my BlockingSupplier
up for posterity, but either of these Future
implementations would be more standard, and work just the same.
您基本上需要一个拥有阻止 get )
方法。类似的东西:
You basically need a holder class with a blocking get()
method. Something like this:
public class BlockingSupplier<E> implements Supplier<E> {
private final CountDownLatch latch = new CountDownLatch(1);
private volatile E value;
public synchronized void set(E value) {
checkState(latch.getCount() > 0, "Cannot call set more than once.");
this.value = value;
latch.countDown();
}
@Override
public E get() {
latch.await(); // will block until set() is called
return value;
}
}
然后你可以这样使用:
BlockingSupplier<Runnable> supplier = new BlockingSupplier<>();
// Pass the BlockingSupplier to our callback
DecoratorCallback myAction = new DecoratorCallback(supplier);
// Register the callback, and set the BlockingSupplier to the old callback
supplier.set(register(myAction));
其中 DecoratorCallback
的 run()
如下所示:
public void run() {
// do my work
// This will block until supplier.set() returns
originalCallbackSupplier.get().run();
}
由于durron597提到有更好的方法来设计回调API, API的问题,这似乎是合理的。
As durron597 mentions there are better ways to design a callback API, but given the API in the question, this seems reasonable.