गतिशील Proxy का उपयोग करना संभव है।
सबसे आसान तरीका वांछित इंटरफ़ेस में भी आपके Mux.create()
कॉल के पहले पैरामीटर के रूप में पास करना है। अन्यथा, आपको प्रदान किए गए सभी कंक्रीट श्रोता उदाहरणों से वांछित इंटरफ़ेस का अनुमान लगाने के लिए प्रतिबिंब का उपयोग करना होगा (यह निर्धारित करना मुश्किल है कि सभी श्रोता ऑब्जेक्ट्स सामान्य रूप से कई इंटरफेस लागू करते हैं)। इस प्रकार,
public class Mux {
/**
* @param targetInterface
* the interface to create a proxy for
* @param instances
* the concrete instances to delegate to
* @return a proxy that'll delegate to all the arguments
*/
@SuppressWarnings("unchecked")
public static <T> T create(Class<T> targetInterface, final T... instances) {
ClassLoader classLoader = targetInterface.getClassLoader();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
for (T instance : instances) {
m.invoke(instance, args);
}
return null;
}
};
return (T) Proxy.newProxyInstance(classLoader,
new Class<?>[] { targetInterface }, handler);
}
}
जो तुम का प्रयोग करेंगे, उदाहरण के लिए:
Apple apple = new Apple();
AppleListener l1 = new AppleListenerA();
AppleListener l2 = new AppleListenerB();
apple.setListener(Mux.create(AppleListener.class, l1, l2));
apple.doSomething(); // will notify all listeners
यह केवल एक गतिशील Proxy
कि लक्ष्य प्रकार के लिए डाला जाता है बनाकर काम करता है
यहाँ यह की कमी है T
। वह प्रॉक्सी InvocationHandler
का उपयोग करती है जो कि कंक्रीट उदाहरणों को प्रॉक्सी में केवल सभी विधि कॉल का प्रतिनिधित्व करती है।
ध्यान दें कि जबकि सामान्य रूप में मैं सभी मापदंडों और स्थानीय चर जहां भी संभव को अंतिम रूप देने, मैं केवल T... instances
इस मामले में अंतिम रूप दे दिया तथ्य यह है कि अगर instances
था उजागर करने के लिए नहीं अंतिम है, तो एक गुमनाम आंतरिक वर्ग के भीतर यह संदर्भित नहीं होगा अनुमति दी जायेगी (आपको एक अलग विधि में परिभाषित आंतरिक कक्षा के अंदर एक गैर-अंतिम परिवर्तनीय तर्कों का संदर्भ नहीं मिल सकता है ")।
यह भी ध्यान दें कि उपरोक्त मानते हैं कि वास्तविक विधि कॉल किसी भी सार्थक (या उपयोगी) मान वापस नहीं लौटाती है, इसलिए handler
सभी विधि कॉल के लिए null
भी लौटाता है। यदि आप रिटर्न वैल्यू एकत्र करना चाहते हैं और उन्हें सार्थक तरीके से वापस करना चाहते हैं तो आपको थोड़ा और कोड जोड़ना होगा।
वैकल्पिक रूप से, एक सब दिया instances
आम इंटरफेस वे सभी को लागू निर्धारित करने के लिए निरीक्षण किया है, और सभी newProxyInstance()
करने के लिए उन पारित कर सकते हैं। यह Mux.create()
को अपने व्यवहार पर कुछ नियंत्रण के नुकसान पर उपयोग करने के लिए बहुत सुविधाजनक बनाता है।
/**
* @param instances
* the arguments
* @return a proxy that'll delegate to all the arguments
*/
@SuppressWarnings("unchecked")
public static <T> T create(final T... instances) {
// Inspect common interfaces
final Set<Class<?>> commonInterfaces = new HashSet<Class<?>>();
commonInterfaces.addAll(Arrays.asList(instances[0].getClass()
.getInterfaces()));
// Or skip instances[0]
for (final T instance : instances) {
commonInterfaces.retainAll(Arrays.asList(instance.getClass()
.getInterfaces()));
}
// Or use ClassLoader.getSystemClassLoader();
final ClassLoader classLoader = instances[0].getClass().getClassLoader();
// magic
final InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(final Object proxy, final Method m, final Object[] args)
throws Throwable {
for (final T instance : instances) {
m.invoke(instance, args);
}
return null;
}
};
final Class<?>[] targetInterfaces = commonInterfaces
.toArray(new Class<?>[commonInterfaces.size()]);
return (T) Proxy.newProxyInstance(classLoader, targetInterfaces,
handler);
}
यदि सभी श्रोताओं ने 'ऐप्पल लिस्टनर' इंटरफ़ेस को लागू किया है, तो मुझे एक प्रतिबिंब, न ही, बी) जेनेरिक की आवश्यकता नहीं दिखाई देती है। बस उन्हें सब कुछ ले लो और उन्हें अपने 'मुक्स' में कहीं भी 'सूची' में जोड़ें और फिर से करें। या क्या मैं कुछ न कुछ भूल रहा हूं? –
क्या आप अपने मल्टीप्लेक्सर के बारे में अपने दिमाग में क्या है इसके बारे में अधिक समझा सकते हैं? क्योंकि एलिस्टेयर इज़राइल ने कहा था कि वही बात मेरे दिमाग में आई थी। –
जबकि यह आपके लिए लक्षित है, इसके अलावा वे एक [प्रॉक्सी] (http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html) कक्षा का उपयोग कर सकते हैं। यह एक ऑब्जेक्ट बनाता है जो दिए गए वर्ग की तरह दिखता है लेकिन इसके कॉल को संसाधित करने के लिए हैंडलर को कॉल करता है, हैंडलर श्रोताओं के माध्यम से फिर से चला सकता है। – BevynQ