2008-12-19 19 views
19

मैं इस दृष्टिकोण की योग्यताओं पर चर्चा नहीं करना चाहता, बस यह संभव है। मेरा मानना ​​है कि जवाब "नहीं" है। लेकिन शायद कोई मुझे आश्चर्यचकित करेगा!जावा में बंदर पैच करना संभव है?

कल्पना कीजिए कि आपके पास कोर विजेट क्लास है। इसमें एक विधि calculateHeight() है, जो ऊंचाई को लौटाती है। ऊंचाई बहुत बड़ी है - इसका परिणाम बटन (कहें) में बहुत बड़ा है। आप अपना खुद का नाइसविड्ज बनाने के लिए डिफॉल्ट विजिट का विस्तार कर सकते हैं, और एक अच्छा आकार वापस करने के लिए अपने calculateHeight() को कार्यान्वित कर सकते हैं।

अब लाइब्रेरी क्लास विंडोडिस्प्लेफ़ैक्टरी, एक जटिल जटिल विधि में डिफ़ॉल्ट विजिट को तुरंत चालू करता है। आप इसे अपने नाइसविड्ज का उपयोग करना चाहते हैं। फैक्ट्री क्लास की विधि इस तरह दिखती है:

public IWidget createView(Component parent) { 
    DefaultWidget widget = new DefaultWidget(CONSTS.BLUE, CONSTS.SIZE_STUPIDLY); 

    // bunch of ifs ... 
    SomeOtherWidget bla = new SomeOtherWidget(widget); 
    SomeResultWidget result = new SomeResultWidget(parent); 
    SomeListener listener = new SomeListener(parent, widget, flags); 

    // more widget creation and voodoo here 

    return result; 
} 

यह सौदा है। परिणाम में अन्य ऑब्जेक्ट्स के पदानुक्रम के भीतर डिफ़ॉल्ट Widget गहराई है। प्रश्न - इस फैक्ट्री विधि को अपने नाइसविड्ज का उपयोग करने के लिए कैसे प्राप्त करें? या कम से कम अपना खुद का calculateHeight() प्राप्त करें। आदर्श रूप में, मैं बंदर DefaultWidget पैच ताकि उसके calculateHeight सही काम किया करने में सक्षम होना चाहते हैं ...

public class MyWindowDisplayFactory { 
    public IWidget createView(Component parent) { 
     DefaultWidget.class.setMethod("calculateHeight", myCalculateHeight); 
     return super.createView(parent); 
    } 
} 

कौन है जो मैं अजगर, रूबी, आदि में कर सकता है मैं का आविष्कार किया गया है नाम setMethod() हालांकि। अन्य विकल्प मेरे लिए खुले हैं:

  • कॉपी करने और अपने ही वर्ग है कि कारखाने वर्ग
  • से विरासत विजेट है कि बहुत बड़ा

हैं के साथ जीने में createView() विधि के कोड को पेस्ट फैक्ट्री क्लास को बदला नहीं जा सकता - यह कोर प्लेटफार्म एपीआई का हिस्सा है। मैंने विजेट पर पहुंचने के लिए लौटाए गए परिणाम पर प्रतिबिंबित करने की कोशिश की (अंत में) जोड़ा गया, लेकिन यह कई विजेट-परतों को नीचे चला गया है और कहीं और यह अन्य सामानों को शुरू करने के लिए उपयोग किया जाता है, जिससे अजीब दुष्प्रभाव होते हैं।

कोई विचार? मेरा समाधान अब तक कॉपी-पेस्ट जॉब है, लेकिन यह एक पुलिस है जिसके लिए प्लेटफार्म के नए संस्करणों में अपग्रेड करते समय पैरेंट फैक्ट्री क्लास में बदलावों की ट्रैकिंग की आवश्यकता होती है, और मुझे अन्य विकल्पों को सुनने में दिलचस्पी होगी।

उत्तर

9

शायद आप उस कार्य को कॉल करने के लिए पहलू ओरिएंटेड प्रोग्रामिंग का उपयोग कर सकते हैं और इसके बजाय अपना संस्करण वापस कर सकते हैं?

वसंत कुछ एओपी कार्यक्षमता प्रदान करता है लेकिन अन्य पुस्तकालय भी हैं जो इसे भी करते हैं।

+0

अच्छा और संभवतः निकटतम वास्तविक समाधान लगता है। शायद स्प्रिंग निर्भरता जोड़ने के लिए थोड़ी अधिक मात्रा में जहां इस फिक्सअप के लिए ऐप में कोई भी मौजूद नहीं था। एक कस्टम क्लास लोडर ग्रहण आरसीपी के साथ अच्छी तरह से खेल नहीं सकता है, जिसका मैं भी उपयोग करता हूं ... – richq

+2

आपको एओपी करने के लिए वसंत की आवश्यकता नहीं है, बस AspectJ प्राप्त करें। एक ग्रहण प्लगइन भी है: http://www.eclipse.org/aspectj/ –

6

एक बदसूरत समाधान सामान्य कार्यान्वयन की तुलना में क्लासपाथ पर पहले डिफ़ॉल्ट विवाद (उसी FQCN के साथ) का अपना कार्यान्वयन करना होगा। यह एक भयानक हैक है, लेकिन हर दूसरे दृष्टिकोण जिसे मैं सोच सकता हूं वह भी बदतर है।

+0

दुर्भाग्य से मैं इसे उपयोग करने के लिए कोई रास्ता नहीं के साथ * वास्तविक * DefaultWidget के 99% का उपयोग करना चाहते पहुंचते हैं। – richq

0

calculateHeight को छोड़कर यह कर एक आवरण IWidget को लागू बनाने के लिए हो सकता है, वास्तविक विजेट के लिए सभी कॉल सौंपने, की वस्तु उन्मुख तरह से, कुछ की तरह:

class MyWidget implements IWidget { 
    private IWidget delegate; 
    public MyWidget(IWidget d) { 
     this.delegate = d; 
    } 
    public int calculateHeight() { 
     // my implementation of calculate height 
    } 
    // for all other methods: { 
    public Object foo(Object bar) { 
     return delegate.foo(bar); 
    } 
} 

इस काम करने के लिए के लिए, आप की जरूरत है विजेट की सभी रचनाओं को अवरुद्ध करें जिन्हें आप प्रतिस्थापित करना चाहते हैं, जिसका अर्थ है विजेटफैक्टरी के लिए एक समान रैपर बनाना। और आप किस विजेटफैक्टरी का उपयोग करने के लिए कॉन्फ़िगर करने में सक्षम होना चाहिए।

यह भी कोई ग्राहक IWidget वापस DefaultWidget को कास्ट करने के लिए कोशिश कर रहा है पर निर्भर करता है ...

+0

यह stategy डिजाइन पैटर्न, और एक क्लासिक जावा उपकरण है। बंदर पैच के साथ कुछ भी करने के लिए नहीं। आप बंदर पैच पसंद नहीं कर सकते हैं, लेकिन यह एक बहुत ही विशेष समस्या के लिए एक anwser है। –

+0

बिल्कुल, मैं इसे एक संभावित विकल्प के रूप में पोस्ट कर रहा हूं। यहां बहुत सारे विकल्प हैं, जो कि वास्तविक परिदृश्य पर निर्भर है, वास्तविक परिदृश्य पर निर्भर करता है: प्रश्न, लचीलापन, मंच में एपीआई की विस्तार संभावनाएं आगे/पीछे संगत आदि होने की आवश्यकता है। –

0

केवल सुझाव मैं के बारे में सोच सकते हैं: पुस्तकालय एपीआई के माध्यम से

  1. खुदाई वहाँ कुछ तरीका है देखने के लिए डिफ़ॉल्ट और आकार बदलने के ओवरराइडिंग।आकार स्विंग में भ्रमित हो सकता है (कम से कम मेरे लिए), सेट न्यूनतम, सेटमैक्सिम, setdefault, setDefaultOnThursday, ...। यह संभव है कि एक रास्ता है। यदि आप पुस्तकालय डिजाइनर से संपर्क कर सकते हैं तो आपको एक ऐसा उत्तर मिल सकता है जो अप्रिय हैकिंग की आवश्यकता को कम करेगा।

  2. शायद फैक्ट्री का विस्तार केवल कुछ डिफ़ॉल्ट आकार पैरामीटर को ओवरराइड करना है? कारखाने पर निर्भर करता है लेकिन यह संभव हो सकता है।

ही नाम के साथ एक वर्ग का निर्माण, केवल अन्य विकल्प हो सकता है के रूप में अन्य लोगों ने बताया है कि यह बदसूरत है और आप इसे भूल जाते हैं और जब आप API लाइब्रेरी को अपडेट करने या एक अलग में तैनात सामान तोड़ने के लिए उत्तरदायी हैं पर्यावरण और भूल जाओ कि आपने क्लासपाथ को इस तरह क्यों स्थापित किया था।

+0

मैं "setMinimumNoReallyIMeanItStopIgnoringMe" विधि की तलाश में रहता हूं। –

+0

हे - यह वास्तव में इससे भी बदतर है - प्रश्न में कोड स्विंग भी नहीं है। एपीआई को देखते हुए, यह निर्भरता इंजेक्शन के लिए begs, लेकिन मैं देख सकता हूं कि यह क्यों नहीं है (चीजों को सरल रखने के लिए)। हो हम! – richq

3

बस मेरे कांसेप्ट आईडिया,

ऐसा नहीं है कि AOP उपयोग करते हैं, बाईटकोड इंजीनियरिंग तरीके के साथ, calculateHeight पद्धति के लिए एक पहलू इंजेक्षन करना संभव है।

फिर, आप थ्रेडलोकल या अन्य चर द्वारा पैच सक्षम कर सकते हैं।

-1

ठीक है, मैं सुझाव पोस्ट करने का प्रयास करता रहता हूं, और फिर मैं देखता हूं कि वे काम नहीं करेंगे या आपने पहले ही उल्लेख किया है कि आपने उन्हें आजमाया है।

सबसे अच्छा समाधान मैं सोच सकता हूं कि विंडोडिस्प्लेफैक्ट्री को उपclass करना है, फिर उपclass की createView() विधि में, पहले super.createView() पर कॉल करें, फिर विजेट को पूरी तरह फेंकने के लिए लौटाई गई ऑब्जेक्ट को संशोधित करें और इसे एक उदाहरण के साथ बदलें उपclass के जो आप चाहते हैं। लेकिन विजेट को सामान शुरू करने के लिए उपयोग किया जाता है, इसलिए आपको उन सभी को बदलना होगा।

तब मैं createView() से लौटे ऑब्जेक्ट पर प्रतिबिंब का उपयोग करने और चीजों को ठीक करने की कोशिश करने के बारे में सोचता हूं, लेकिन फिर, यह बालों वाली है क्योंकि विजेट के साथ बहुत सारी चीज़ें शुरू की गई थीं। मुझे लगता है कि मैं उस दृष्टिकोण का उपयोग करने की कोशिश करूंगा, हालांकि, अगर कॉपी और चिपकाने पर इसे उचित ठहराना पर्याप्त था।

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

+0

हाँ, createView में अतिरिक्त new'd कक्षाओं में एक उचित मात्रा में किया गया है - अंत में प्रतिबिंब + फिक्स अप शायद होगा कॉपी-पेस्टिंग की तुलना में अधिक नाजुक (विजेटफैक्टरी के नए संस्करणों के साथ बनाए रखने के लिए कठिन) रहे हैं। – richq

2

cglib एक जावा लाइब्रेरी है जो बंदर पैचिंग के समान कुछ चीजें कर सकती है - यह कुछ व्यवहार बदलने के लिए रनटाइम पर बाइटकोड में हेरफेर कर सकती है। मुझे यकीन नहीं है कि यह वही कर सकता है जो आपको चाहिए, लेकिन यह एक लायक है ...

+1

बाइट-कोड में हेरफेर करने के लिए अन्य टूल्स: http://jakarta.apache.org/bcel/ http://asm.objectweb.org/ –

0

आप PowerMock/Mockito जैसे उपकरणों का उपयोग करने का प्रयास कर सकते हैं। यदि आप परीक्षण में नकल कर सकते हैं, तो आप भी उत्पादन में नकली कर सकते हैं।

हालांकि इन उपकरणों को वास्तव में इस तरह से उपयोग करने के लिए डिज़ाइन नहीं किया गया है, इसलिए आपको पर्यावरण को स्वयं तैयार करना होगा और परीक्षणों में आपके जैसे जुनीट धावकों का उपयोग करने में सक्षम नहीं होंगे ...

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