Java.lang.reflect। विकल्प के लिए अमूर्त वर्ग (इंटरफेस के बजाय) के परदे के पीछे बनाने के लिए


89

प्रलेखन के अनुसार :

[ java.lang.reflect.] Proxyडायनेमिक प्रॉक्सी क्लास और इंस्टेंसेस बनाने के लिए स्थैतिक तरीके प्रदान करता है, और यह उन तरीकों द्वारा बनाए गए सभी डायनेमिक प्रॉक्सी क्लासेज का सुपरक्लास भी है।

newProxyMethodविधि (गतिशील प्रॉक्सी पैदा करने के लिए जिम्मेदार) निम्नलिखित हस्ताक्षर हैं:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                             throws IllegalArgumentException

दुर्भाग्य से, यह एक गतिशील प्रॉक्सी को उत्पन्न करने से रोकता है जो एक विशिष्ट अमूर्त वर्ग ( विशिष्ट इंटरफेस को लागू करने के बजाय ) को बढ़ाता है । यह समझ में आता है, "सभी गतिशील परदे के पीछे का सुपरक्लास" है, जिससे दूसरे वर्ग को सुपरक्लास होने से रोका जा सकता है।java.lang.reflect.Proxy

इसलिए, क्या ऐसे कोई विकल्प हैं java.lang.reflect.Proxyजो एक विशिष्ट अमूर्त वर्ग से विरासत में उत्पन्न होने वाली गतिशील परदे के पीछे उत्पन्न कर सकते हैं , जो अमूर्त विधियों को आह्वान करने वाले हैंडलर को पुनर्निर्देशित कर सकते हैं ?

उदाहरण के लिए, मान लीजिए कि मेरे पास एक सार वर्ग है Dog:

public abstract class Dog {

    public void bark() {
        System.out.println("Woof!");
    }

    public abstract void fetch();

}

क्या कोई ऐसा वर्ग है जो मुझे निम्नलिखित कार्य करने की अनुमति देता है?

Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);

dog.fetch(); // Will be handled by the invocation handler
dog.bark();  // Will NOT be handled by the invocation handler

जवाबों:


123

यह Javassist (देखें ProxyFactory) या CGLIB का उपयोग करके किया जा सकता है ।

Javassist का उपयोग कर एडम का उदाहरण:

मैंने (एडम पेन्न्टर) ने इस कोड को Javassist का उपयोग करते हुए लिखा है:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Dog.class);
factory.setFilter(
    new MethodFilter() {
        @Override
        public boolean isHandled(Method method) {
            return Modifier.isAbstract(method.getModifiers());
        }
    }
);

MethodHandler handler = new MethodHandler() {
    @Override
    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        System.out.println("Handling " + thisMethod + " via the method handler");
        return null;
    }
};

Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
dog.bark();
dog.fetch();

जो इस उत्पादन का उत्पादन करता है:

Woof!
विधि हैंडलर के माध्यम से सार्वजनिक अमूर्त शून्य mock.Dog.fetch () को हैंडल करना

10
+1: वास्तव में मुझे क्या चाहिए! मैं आपके उत्तर को अपने नमूना कोड के साथ संपादित करूंगा।
एडम पेन्न्टर

proxyFactory.setHandler()पदावनत किया गया है। कृपया उपयोग करें proxy.setHandler
AlikElzin-kilaka

@axtavt ऑब्जेक्ट "डॉग" है जो उपरोक्त कोड में कार्यान्वयन या इंटरफ़ेस है?
stackoverflow

-7

ऐसे मामले में आप क्या कर सकते हैं एक प्रॉक्सी हैंडलर है जो आपके अमूर्त वर्ग के मौजूदा तरीकों को कॉल पुनर्निर्देशित करेगा।

आपको बेशक इसे कोड करना होगा, हालांकि यह काफी सरल है। अपना प्रॉक्सी बनाने के लिए, आपको उसे a देना होगा InvocationHandler। फिर आपको केवल invoke(..)अपने मंगलाचरण हैंडलर की विधि प्रकार की जांच करनी होगी । लेकिन सावधान रहें: आपको अपने हैंडलर से संबंधित अंतर्निहित ऑब्जेक्ट के खिलाफ विधि प्रकार की जांच करनी होगी, न कि आपके सार वर्ग के घोषित प्रकार के खिलाफ।

अगर मैं एक उदाहरण के रूप में आपका कुत्ता वर्ग लेता हूं, तो आपके मंगलाचरण की आह्वान विधि इस तरह दिख सकती है (मौजूदा संबद्ध कुत्ते उपवर्ग के साथ .. अच्छी तरह से ... dog)

public void invoke(Object proxy, Method method, Object[] args) {
    if(!Modifier.isAbstract(method.getModifiers())) {
        method.invoke(dog, args); // with the correct exception handling
    } else {
        // what can we do with abstract methods ?
    }
}

हालांकि, कुछ ऐसा है जो मुझे आश्चर्यचकित करता है: मैंने एक dogवस्तु के बारे में बात की है । लेकिन, जैसा कि डॉग क्लास सार है, आप उदाहरण नहीं बना सकते हैं, इसलिए आपके पास मौजूदा उपवर्ग हैं। इसके अलावा, प्रॉक्सी स्रोत कोड के एक कठोर निरीक्षण के रूप में, आपको पता चल सकता है (Proxy.java:362 पर) कि एक क्लास ऑब्जेक्ट के लिए प्रॉक्सी बनाना संभव नहीं है जो एक इंटरफ़ेस का प्रतिनिधित्व नहीं करता है)।

इसलिए, वास्तविकता के अलावा , आप जो करना चाहते हैं वह पूरी तरह से संभव है।


1
कृपया मुझे अपने उत्तर को समझने की कोशिश करते हुए सहन करें ... मेरे विशेष मामले में, मैं चाहता हूं कि प्रॉक्सी क्लास (रनटाइम पर उत्पन्न) Dogउदाहरण के लिए उपवर्ग हो , उदाहरण के लिए, मैं स्पष्ट रूप से एक Poodleक्लास लिख रहा हूं जो लागू होता है fetch())। इसलिए, dogतरीकों को लागू करने के लिए कोई चर नहीं है ... माफ करना अगर मैं भ्रमित कर रहा हूं, तो मुझे इस पर थोड़ा और सोचना होगा।
एडम पेन्न्टर

1
@ अदम - आप गतिशील रूप से कुछ बाइटकोड हेरफेर (CGLib मुझे लगता है कि इस तरह से कुछ करता है) के बिना रनटाइम पर उपवर्ग बना सकते हैं। संक्षिप्त उत्तर यह है कि गतिशील परदे के पीछे इंटरफेस का समर्थन करते हैं, लेकिन अमूर्त वर्गों का नहीं, क्योंकि दोनों बहुत अलग अवधारणाएं हैं। यह एक तरह से गतिशील रूप से प्रॉक्सी अमूर्त वर्गों के लिए एक तरह से सोचने के लिए लगभग असंभव है।
आंद्रेज डॉयल

1
@Andrzej: मैं समझता हूं कि जो मैं पूछ रहा हूं उसके लिए बायटेकोड हेरफेर की आवश्यकता है (वास्तव में, मैंने पहले से ही एएसएम का उपयोग करके अपनी समस्या का समाधान लिख दिया है)। मैं यह भी समझता हूं कि जावा के डायनेमिक प्रॉक्सी केवल इंटरफेस का समर्थन करते हैं। शायद मेरा सवाल पूरी तरह से स्पष्ट नहीं था - मैं पूछ रहा हूं कि क्या कोई अन्य वर्ग (जो कुछ और है java.lang.reflect.Proxy) उपलब्ध है जो मुझे चाहिए।
एडम पेन्न्टर

2
खैर, लंबी चीजों को छोटा करने के लिए ... नहीं (कम से कम मानक जावा कक्षाओं में)। बाइटकोड हेरफेर का उपयोग करके, आकाश सीमा है!
रिड्यूडेल

9
मैं नीच है क्योंकि यह वास्तव में सवाल का जवाब नहीं है। ओपी ने कहा कि वह एक वर्ग को प्रॉक्सी करना चाहता है, एक इंटरफ़ेस नहीं, और यह जानता है कि यह java.lang.reflect.oxy के साथ संभव नहीं है। आप बस उस तथ्य को दोहराते हैं और कोई अन्य समाधान नहीं देते हैं।
jcsahnwaldt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.