2011-10-20 22 views
5

का उपयोग करके कुछ मदद की ज़रूरत है, मैं ऑब्जर्वर पैटर्न के समान, मेरे एप्लिकेशन में होने वाली घटनाओं का जवाब देने के लिए एक सिस्टम बनाने की कोशिश कर रहा हूं। अपने सिस्टम में, EventProducer रों ट्रिगर घटनाओं और EventConsumer रों उन घटनाओं पर प्रतिक्रिया दें और दो एक केंद्रीय हब के माध्यम से जुड़े हुए हैं:जावा जेनरिक

पल के लिए, मैं EventProducer ध्यान न दें और EventHub और EventConsumer पर ध्यान केंद्रित करने जा रहा हूँ:

interface EventConsumer<E extends Event> { 
    void respondToEvent(E event); 
} 

class EventHub { 
    private HashMap<Class</*event type*/>, HashSet<EventConsumer</*event type*/>>> subscriptions; 
    public <E extends Event> void fireEvent(E event) { 
     /* For every consumer in the set corresponding to the event type { 
      consumer.respondToEvent(event); 
     } */ 
    } 
    public <E extends Event> void subscribeToEvent(EventConsumer<E> consumer) { 
     /* Insert consumer into the set corresponding to E */ 
    } 
} 
समस्या

HashMap की घोषणा में निहित है: मैं

HashMap<Class<E extends Event>, HashSet<EventConsumer<E>>> 
// or 
<E extends Event> HashMap<Class<E>, HashSet<EventConsumer<E>>> 
की तरह कुछ करने के लिए सक्षम होना चाहते हैं

तो EventConsumer एक ही प्रकार Class है द्वारा parameterized है, लेकिन सबसे करीब मैं प्राप्त कर सकते हैं

HashMap<Class<? extends Event>, HashSet<EventConsumer<? extends Event>>> 

है लेकिन तब यह एक HashSet<EventConsumer<MouseClickEvent>> तरह बातें Class<KeyPressEvent> करने के लिए आवंटित किया जा रहा की अनुमति होगी, दोनों KeyPressEvent और MouseClickEvent उपवर्ग यह सोचते हैं कि Event

एक दूसरी समस्या subscribeToEvent में है: मैं उपभोक्ता

subscriptions.get(E.class).put(consumer) 

में की तरह, सही सेट अपने घटना के लिए इसी में स्टोर करने के लिए सक्षम होना चाहिए, लेकिन मैं रन-टाइम में ई की श्रेणी नहीं मिल सकता है ।

मैं इन समस्याओं को कैसे हल कर सकता हूं? क्या मैं इस बारे में गलत तरीके से जा रहा हूं?

उत्तर

1

आप जेनिक्स को EventConsumer कक्षा से निकाल सकते हैं। लेकिन आपको EventConsumer के प्रत्येक कार्यान्वयन में इवेंट ऑब्जेक्ट डालना होगा।

interface EventConsumer { 
    void respondToEvent(Event event); 
} 

class ClickEventConsumer implements EventConsumer { 
    public void respondToEvent(Event event){ 
    ClickEvent ce = (ClickEvent)event; 
    //... 
    } 
} 

class EventHub { 
    private HashMap<Class<? extends Event>, HashSet<EventConsumer>> subscriptions; 

    public void fireEvent(Event event) { 
    HashSet<EventConsumer> consumers = subscriptions.get(event.getClass()); 
    if (consumers != null){ 
     for (EventConsumer ec : consumers){ 
     ec.respondToEvent(event); 
     } 
    } 
    } 

    public void subscribeToEvent(Class<? extends Event> clazz, EventConsumer consumer) { 
    HashSet<EventConsumer> consumers = subscriptions.get(clazz); 
    if (consumers == null){ 
     consumers = new HashSet<EventConsumer>(); 
     subscriptions.put(clazz, consumers); 
    } 
    consumers.add(consumer); 
    } 
} 
+0

असल में, मुझे यह दृष्टिकोण पसंद है। मूल रूप से, मैं 'क्लास कुछ कॉन्स्यूमर इम्प्लमेंट्स इवेंट कॉन्स्यूमर , इवेंट कॉन्स्यूमर ' जैसी कुछ करने में सक्षम होना चाहता था, लेकिन स्पष्ट रूप से आप ऐसा नहीं कर सकते (जो मुझे लगता है)।क्या कोई जवाब है कि मैं किसी उपभोक्ता पर 'EventToEvent' में स्विच से बचने के लिए 'ईवेंट' पॉलिमॉर्फिज्म का कुछ रूप प्राप्त कर सकता हूं? 'शून्य प्रतिक्रिया की तरह (ClickEvent) की तरह; शून्य जवाब ToEvent (KeyPressEvent); '? –

+0

@AustinHyde मुझे नहीं पता। मैं इसके साथ खेल रहा था, लेकिन मुझे 'EventHub' में सभी जेनेरिक भ्रम पैदा किए बिना ऐसा करने का अच्छा तरीका नहीं मिला। आपको कोड की पठनीयता पर भी विचार करना चाहिए। यहां तक ​​कि अगर यह चीजों को थोड़ा अक्षम करता है, अगर समय के साथ बनाए रखना आसान है, तो मुझे लगता है कि यह इसके लायक है (जब तक कि आप कंप्यूटर गेम या सर्च इंजन या कुछ मिलिसेकंड की गणना नहीं करते)। मेरे लिए, वे सभी जेनेरिक कोड को पढ़ने और समझने के लिए कठिन बनाते हैं। – Michael

1

मानचित्र का सवाल है, मैं इसे इस रूप में छोड़ चाहते हैं:

HashMap<Class<? extends Event>, Set<EventConsumer<? extends Event>>> subscriptions; 

और फिर जैसे पैरामिट्रीकृत एक्सेसर तरीकों का उपयोग:

<E extends Event> void addSubscription(Class<E> eventClass, EventConsumer<? super E> eventConsumer) 

<E extends Event> Set<EventConsumer<? super E>> getSubscriptions(Class<E> eventClass) 

के रूप में आप पहले ही बताया आप घटना वर्ग प्राप्त नहीं कर सकता रनटाइम पर, इसलिए आपको इसे अपने एपीआई उपयोगकर्ताओं द्वारा प्रदान किया जाना होगा उदाहरण के लिए ऊपर दिए गए addSubscription के विधि हस्ताक्षर के साथ।

0

आप अपने EventHub क्लास को पैरामीटर क्यों नहीं करते? कोई चुनौती?

interface EventConsumer<E extends Event> { 
void respondToEvent(E event); 
} 

class EventHub<E extends Event> { 
private HashMap<Class<E>, HashSet<EventConsumer<E>>> subscriptions; 

public void fireEvent(E event) { 
/* 
* For every consumer in the set corresponding to the event type { 
* consumer.respondToEvent(event); } 
*/ 
    } 

    public void subscribeToEvent(EventConsumer<E> consumer) { 
    /* Insert consumer into the set corresponding to E */ 
} 
} 

और फिर अपने सभी फ़ंक्शन हस्ताक्षरों में ई का उपयोग करें।

संपादित करें 1: ठीक है, के बाद से मैं और अधिक स्पष्ट रूप में अपने प्रश्न को समझते हैं, यहाँ हम चले:

अपने EventConsumer कक्षा एक EventType (रों) है कि यह समर्थन करता है/हैंडल रख सकते हैं। यहां तक ​​कि टाइप एक enum है। अपने मानचित्र में आप उपभोक्ता को इवेंट टाइप के खिलाफ स्टोर करते हैं।

+0

यह एक विकल्प नहीं है, क्योंकि 'EventHub' को एक से अधिक प्रकार के' ईवेंट 'को संभालने की आवश्यकता है। अगर मैं 'नया EventHub ' करता हूं, तो 'EventHub' केवल' KeyPressEvent 'के लिए काम करेगा, उदाहरण के लिए नहीं। 'MouseClickEvent' –

+0

आपका EventConsumer क्लास एक इवेंट टाइप (एस) रख सकता है जो इसे समर्थन/हैंडल करता है। यहां तक ​​कि टाइप एक enum है। अपने मानचित्र में आप उपभोक्ता को इवेंट टाइप के खिलाफ स्टोर करते हैं। –

2

आप क्या कर सकते हैं मानचित्र को अपने स्वयं के पैरामीटरयुक्त वर्ग के साथ लपेटना है। कक्षा में पैरामीटर दिया - आप इसे मानचित्र में उपयोग कर सकते हैं।ऐसा ही कुछ:

public class EventsMap<E extends Event> { 
    HashMap<Class<E>, HashSet<E>> map; 
} 

सदस्यता लेने के लिए के रूप में - मैं ty1824 के जवाब का उपयोग करेंगे ..

+1

क्या कोई कारण है कि मैं उप-वर्ग के बजाय इसे लपेटना चाहता हूं: 'क्लास इवेंट्स मैप <ई इवेंट बढ़ाता है> हैश मैप , हैशसेट >> ' –

+1

@ ऑस्टिन हां हैं: 1. आप केवल उन तरीकों का सार्वजनिक जो आपके कार्यान्वयन द्वारा बेहतर encapsulation 2 प्रदान करते हैं। यह आपको यूनिट के मूल हैश मैप 3 परीक्षण के बिना कार्यान्वयन का परीक्षण करने की अनुमति देगा। आप विरासत priciple http://e.wikipedia.org पर पक्ष संरचना के साथ चिपके रहेंगे/wiki/composition_over_inheritance – Gandalf

+0

@ गैंडफ वेल * यह * एक दिलचस्प अवधारणा है जिसे मैंने नहीं सोचा था। मुझे उसमें और अधिक देखने की आवश्यकता होगी, लेकिन मुझे लगता है कि यह वास्तव में इस एप्लिकेशन में से अधिक के लिए इस एप्लिकेशन में भी लागू हो सकता है ... धन्यवाद एक टन! –

0

खैर, अंत से शुरू:

सबसे पहले, आप वास्तव में कार्यावधि में सामान्य प्रकार पैरामीटर प्रकार प्राप्त कर सकते हैं । यह सिर्फ है कि आप केवल एक विशेष मामले में यह क्या कर सकते हैं:

static class A<E extends EventObject> { 
} 

static class B extends A<MouseEvent> { 
} 

public static void main(String[] args) { 
    System.out.println(B.class.getGenericSuperclass()); 
} 

नोट B गैर सामान्य है, लेकिन एक सामान्य माता पिता से विरासत में मिला है।

सुपर क्लास एक पैरामिट्रीकृत प्रकार है, तो Type वस्तु लौटे सही रूप में वास्तविक प्रकार स्रोत कोड में प्रयोग किया जाता मानकों प्रतिबिंबित करना चाहिए।

चाहे आप इसे किसी भी प्रयोग में डाल सकते हैं, एक अलग सवाल है। मैंने कोशिश नहीं की मैंने जो कोड देखा है, वह स्पष्ट रूप से Class उदाहरण को वर्कअराउंड के रूप में पास करता है।

दूसरा, Map यहां नहीं है (ठीक है, जहां तक ​​मुझे पता है) जेनेरिक के साथ तय किया जा सकता है। आप निश्चित रूप से एक टाइपएफ़ मैप लागू कर सकते हैं, लेकिन मुझे लगता है कि एक और दिलचस्प बात यह है कि: जब आप किसी ईवेंट को फायर करते हैं, तो संभवतः आप इसे इस विशेष ईवेंट क्लास और पर सब्सक्राइब करने वाले सभी को भेजना चाहते हैं, जिन्होंने अपने माता-पिता की सदस्यता ली है । तो बस event.getClass() पर्याप्त से थोड़ा कम होगा।

संबंधित मुद्दे