2011-12-02 20 views
1

我很親密,但我沒有把頭纏到它的周圍。一個通用的EventManager - 在3行代碼之後卡住:-)

我試圖用Java創建(安卓)用默認的東西,事件管理器,例如註冊事件,引發事件,等等...

我想這是一個「通用」的方式,我可以寫這樣的事:

StringChangedEvent event 
     = evManInst.Register<StringChangedEvent>(new StringChangedEvent()); 
event.Publish("Hello"); 

而且在不同的類

StringChangedEvent event 
     = evManInst.Register<StringChangedEvent>(new StringChangedEvent()); 
event.Subscribe(this) 

當然,該實例應該是同一個。我要傳遞對象,因爲我不能新T() - 但也許我在這裏做一些泛型真邪:-)

如果你讀過我eventmanager進行的實行,將第一回路不會編譯 ,因爲不兼容的類型。我該如何解決這個問題?有趣的是,如果你看代碼,它的類型都很好,沒有什麼可以出錯的(在我看來)。

還有一點:我不想創建一個通用的EventManager<StringChangedEvent>,因爲這會將此EventManager限制爲一種類型的事件。並返回EventBase並鑄造它只是醜陋的(但也許唯一的出路?)。

public class EventManager 
    { 
     private HashMap<Class<EventBase>, EventBase> _registeredEvents 
      = new HashMap<Class<EventBase>, EventBase>(); 

     public<T extends EventBase> T Register(T instance) 
     { 
     if (_registeredEvents.containsKey(instance.getClass())) 
     { 
      return _registeredEvents.get(instance.getClass()); 
     } 
     else 
     { 
      return instance; 
     } 
    } 

} 

編輯從Kaediil澄清答案評論

EventManager x = new EventManager<TestEvent>(); 
EventManager x2 = new EventManager(); 

// Not OK 
TestEvent t = x.Register(new TestEvent()); 

// OK (but I want MORE :-) 
TestEvent t2 = (TestEvent)x.Register(new TestEvent()); 

// This to be exact, because then I can do something like this 
TestEvent t2 = x.Register<TestEvent>(new TestEvent()); 

x.Register<TestEvent>(new TestEvent()).CallMethodOfTestEvent(); 
+0

什麼是編譯錯誤? –

+0

不兼容的類型。他希望我返回T,並且他似乎不知道該實例的類型爲T. –

+0

最後兩次調用的Java語法是'x。 註冊',你幾乎不需要使用它。有時候類型推斷算法不能達到你期望的效果,並且它很有用,但通常這隻意味着你的API使用了太多的泛型。 – millimoose

回答

1

下面的代碼應該做你想要什麼:

import java.util.HashMap; 

public class EventManager { 

    private HashMap<Class<? extends EventBase>, EventBase> _registeredEvents 
      = new HashMap<Class<? extends EventBase>, EventBase>(); 


    public <T extends EventBase> T Register(T event) { 
     @SuppressWarnings("unchecked") 
     Class<? extends T> eventType = (Class<? extends T>) event.getClass(); 

     if (_registeredEvents.containsKey(eventType)) { 
      return eventType.cast(_registeredEvents.get(eventType)); 
     } else { 
      _registeredEvents.put(eventType, event); 
      return event; 
     } 
    } 
} 

class EventBase {} 

class ChangeEvent extends EventBase {} 

class Main { 
    public static void main(String[] args) { 
     EventManager em = new EventManager(); 
     ChangeEvent e = em.Register(new ChangeEvent()); 
    } 
} 

編譯器抱怨@SuppressWarnings後面的行,但我認爲它應該是正確的,它只是編譯器魔術圍繞getClass()而不能正確處理這個問題。

您的代碼中的問題是,您無法從HashMap<…, EventBase>中檢索除EventBase之外的其他內容,因爲無法靜態證明這是類型安全。你必須施放某個地方,並且Class.cast可以讓你在執行該方法時執行此操作。 (你也可以用T來「讓編譯器閉嘴」,但這不是一個好主意,因爲它使ClassCastExceptions在使用API​​的代碼中發生,而不是在演員所在的位置。)

+0

哦,我喜歡這個頁面:-)完美的工作,我甚至不需要函數上的<>(這是我犯的一個錯誤,在C#中你做到了,我只是猜測了Java語法......) –

1

試試這個:

public class EventManager <T extends EventBase>{ 

private HashMap<Class<EventBase>, T > _registeredEvents 
= new HashMap<Class<EventBase>, T>(); 



public T Register(T instance) 
{ 
    if (_registeredEvents.containsKey(instance.getClass())) 
    { 
     return _registeredEvents.get(instance.getClass()); 
    } 
    else 
    { 
     return instance; 
    } 
    } 
} 
+0

謝謝,但那隻能讓我走到一半。我知道我是一個討厭的小女孩,但我想(t)工作,t2太長了:-)看到上面編輯過的代碼...... x或x2不會有所作爲,順便說一句。 –

+0

@Christian:您需要聲明變量(在您的編輯中)爲'EventManager x = new EventManager ();',而不是原始類型。 – millimoose

+0

好吧,但這仍然會讓我停留在一個單一的EventManager上,以適合我需要的每種事件類型,或者我錯了嗎?這個想法是隻有一個人,我可能必須堅持演員陣容 - 它不是那麼糟糕,我只是想知道,如果我只是沒有得到泛型的權利... –