2015-08-24 37 views
1

假設我用下面的回調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); 

我想註冊自己的行動,但我想保留任何一組行爲。換句話說,我想我的行動看起來像:

new Runnable() { 
    public void run() { 
    // do my work 

    originalCallback.run(); 
    } 
} 

什麼是提供originalCallbackRunnable最乾淨的方式是什麼?

想到這些天真的解決方案會引入一個時間窗口,其中originalCallback在調用回調時不可用,或者涉及一些複雜的鎖定。

+0

當你說'先前註冊的動作',你的意思是'this'或'callback'? –

+0

也不是傳遞給'register()'的前一個調用的'callback'。與Map.put()返回前一個值的方式相同。 – dimo414

+0

爲什麼不創建一個實現Runnable並在構造函數中提供originalCallback的私有類? – rainkinz

回答

2

經過多次挖掘,我發現了番石榴的SettableFuture和Java 8的CompletableFuture。我將爲後人留下我的BlockingSupplier,但這些Future實現中的任何一個都將更加標準,並且工作原理相同。


你基本上需要一個支架類阻塞get()方法。事情是這樣的:

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)); 

哪裏DecoratorCallbackrun()看起來是這樣的:

public void run() { 
    // do my work 

    // This will block until supplier.set() returns 
    originalCallbackSupplier.get().run(); 
} 

由於durron597提到有到更好的方法設計一個回調API,但考慮到問題中的API,這似乎是合理的。

1

這是擁有API的可怕方式。 Single Responsibility Principle適用於此。你現在正在做它的方式,您可運行的主要職責是:

  1. 不管它的其他工作是
  2. 調用其他的回調。

您的API設計本質上破壞了SRP!每個使用此API的類都已經從getgo中斷了。

幸運的是,你可以很容易地解決這個問題,番石榴的ListenableFuture,它的工作原理是這樣的:

  1. 提交任務
  2. 獲取ListenableFuture對象返回
  3. 附加回調與Futures.addCallback

這樣做可以確保您的系統放置用於管理多線程的代碼,並在發生關係之前發生e地點,以及實際上在另一個地方開展工作的代碼。

+0

回調API超出了我的控制範圍。 – dimo414

+0

@ dimo414那太臭了。但這就是爲什麼沒有人想過以前這樣做。我想你的答案是一個可接受的損害控制解決方案。 – durron597

相關問題