2010-11-09 34 views
1

我目前有一個Java Observer/Observable設置,其中我在Observer.update的Object參數(例如事件ID)內切換某個字段以確定如何處理Observable通知。觀察者設計 - 如何訪問method.invoke範圍?

這將創建像冗長的代碼:

public void update (Observable o, Object arg) { 
    if (arg instanceof Event) { 
     switch (((Event)arg).getID()) { 
      case EVENT_TYPE_A: 
       // do stuff... 
       break; 
      case EVENT_TYPE_B: 
       // do stuff... 
       break; 
      case EVENT_TYPE_C: 
       // do stuff... 
       break; 
     } 
    } 
} 

從ActionScript背景的人,這種感覺不必要的冗長,我...強似觀察者的情況下,我寧願傳遞一個回調方法由Observable直接調用(更具體地說,由一個子類)。然而,我不清楚如何確定方法應該被調用的對象(「擁有」該方法的類實例)。

我可以傳遞一個引用到封裝該方法的實例,但是這味道就像糟糕的OOP。

我吠叫錯了樹嗎?還是有一個乾淨的方式來實現這一目標?

+0

我看到你的困境;這不是觀察者模式。見http://stackoverflow.com/questions/5423125/polymorphism-and-interfaces-in-java-can-polymorphism-be-used-to-implement-interf/5423860#5423860 – 2011-04-02 01:22:15

回答

1

一個更清晰的實現將涉及到事件是否可以由觀察者/觀察者處理到實際觀察者/觀察者本身的邏輯。看起來好像ActionScript已經讓你對Observer模式有了一個有趣的想法。觀察(沒有雙關語,意):

public interface Observer{ 

    public void update(Event arg); 
} 

public class Event{ 

    public int ID; 
} 

public Button implements Observer{ 

    public void update (Event arg){ 

    switch (arg.ID){ 

     case 1: //Buttonsy handle events of type 1 
     //do something useful; 
     break; 
     default: 
     System.out.println("Buttons don't handle events of ID: " + arg.ID); 
     break; 
    } 
    } 
} 

public ProgressBar implements Observer{ 

    public void update (Event arg){ 

    switch (arg.ID){ 

     case 2: //ProgressBars handle events of type 2 and 3 
     //do something useful; 
     break; 
     case 3: 
     //do something else useful; 
     break; 
     default: 
     System.out.println("Progress bars don't handle events of ID: " + arg.ID); 
     break; 
    } 
    } 
} 


public class Subject{ 

private ArrayList<Observer> allUIControls; 

public registerControl(Observer control){ 

    allUIControls.add(control); 
} 

public void updateControls (Event arg) { 

    foreach (Observer control in allUIControls){ 

    //pass the event to each UI control, and let the EVENT decide if it can understand the Event.ID 
    //its not the job of Subject to decide if the Observer is fit to handle the event. THIS IS NOT THE OBSERVER pattern. 
    control.update(arg); 
    } 
} 
} 
+0

是啊,這是我在哪裏馬上。我可以與Observers的事件處理程序中的開關一起生活。它僅僅是一個與ActionScript不同的範例;我看到每個人的利弊。 – ericsoco 2011-04-02 04:53:57

2

這可能是有點遠在左場,但由於Java 5的和最多有仿製藥,既有傳統的觀察者和偵聽模式似乎有點過時了。也就是說,類型現在是java的通用語法。帶有整數ID的事件主要是因爲對常量的開關語句是非常有效的 - 以可讀性爲代價並且通常需要強制轉換來做有用的事情(你可能知道如果ID = 23,Object必須是MouseEvent,但它更好如果你讓編譯器和運行時類型信息爲你處理這個問題,那更安全)。在現代JVM中的現代機器上,效率可能不值得。

所以,如果你沒有結婚,以ID和傳統的觀察者模式,你可能會考慮這樣的事情:

public abstract class Observer<T> { 
    private final Class<T> type; 

    protected Observer(Class<T> type) { 
    this.type = type; 
    } 

    //implement this method; if it returns false, the event (object) 
    //is "consumed" and no other observers should be called 
    public abstract boolean onEvent(T instance); 

    protected final boolean matches(Object obj) { 
    return type.isInstance(obj); 
    } 

    Boolean maybeDispatch(Object o) { 
    if (matches(o)) { 
     return onEvent(type.cast(o)); 
    } 
    return null; 
    } 
} 

這會讓我們(字面)事件的一般觀察;我們切換傳遞在像這樣的物體的類型:

public class Bus { 
    private final List<Observer<?>> observers = new ArrayList<Observer<?>>(); 

    public void registerObserver(Observer<?> observer) { 
    observers.add(observer); 
    } 

    public <T> void onEvent(T t) { 
    Boolean keepGoing; 
    for (Observer<?> obs : observers) { 
     keepGoing = obs.maybeDispatch(t); 
     if (keepGoing != null && !keepGoing.booleanValue()) { 
     break; 
     } 
    } 
    } 
} 

產生的代碼是(稍微)降低效率,但是寫這樣的「觀察者」的一個亞類是無限更具有可讀性。它看起來不像傳統的觀察者模式,但在功能上等同。

如果你還需要一個額外的「事件」參數,你可以做類似的邏輯來參數化兩種類型。

+0

嗯,非常有趣...現在,我想堅持Java的觀察者,但這似乎是一個很好的候選人以後重新設計。我仍然是一個Java noob(如果你沒有猜到)和泛型對我來說是新的,我已經與集合框架一起使用它們。但是我開始感受到它們帶來的靈活性,同時仍然保持類型安全性和編譯時的善良性...... – ericsoco 2011-04-06 05:32:14