2015-08-01 13 views
6

यदि समान इंटरफ़ेस वाले वर्ग समान हैं लेकिन अलग-अलग विधि हस्ताक्षर हैं तो क्या करें?क्या करना है यदि समान इंटरफेस वाले वर्ग समान लेकिन अलग-अलग विधि हस्ताक्षर वाले हैं?

मान लें कि मेरे पास अलग-अलग लागतों की गणना करने के लिए एक परियोजना है (अंतिम लागत कुल प्राप्त करने के लिए)।

मेरे कार्यक्रम में, कई कैलकुलेटर कक्षाएं हैं, अर्थात् ACostCalculator, BCostCalculator और इसी तरह। जब लागत की गणना करने के लिए calculate() विधि लागू की जाती है, तो लागत लागत कंटेनर भी उन लागत कैलकुलेटर को पास किया जाता है। एक अच्छी परिदृश्य में, मैं प्रत्येक लागत कैलकुलेटर के लिए CostCalculator इंटरफ़ेस बना सकता हूं।

हालांकि, विभिन्न लागतों की गणना के लिए विभिन्न संसाधनों की आवश्यकता होती है।

//getResource() are costly method while several costs need this. So do it outside calculate() method. 
ResourceA resourceA = getResourceA(); 
ResourceB resourceB = getResourceB(); 

CostContainer costContainer = new CostContainer(); 
CostCalculator aCostCalculator = new ACostCalculator(); 
... 
CostCalculator eCostCalculator = new ECostCalculator(); 

aCostCalculator.calculate(costContainer); 
bCostCalculator.calculate(costContainer) 
cCostCalculator.calculate(costContainer, resourceA); 
dCostCalculator.calculate(costContainer, resourceA); 
eCostCalculator.calculate(costContainer, resourceA, resourceB); 

तो हस्ताक्षर बिल्कुल वैसा ही है, मैं आसानी से एक पाश कर सकते हैं यह एक ही बार में करना है: मेरे वर्तमान कार्यक्रम में, यह तरह बनाते हैं। हालांकि, चूंकि वे समान लेकिन अलग हैं, इसलिए मैं एक अच्छा इंटरफ़ेस भी नहीं बना सकता।

मुझे यकीन नहीं है कि ऐसा करने के अच्छे तरीके हैं या नहीं। मैं क्या सोचते की

calculate(CostContainer costContainer, List<Object> resources); 

कोई भी विचार में करने के लिए सभी calculate() विधि सामान्यीकरण है सकते हैं? जवाब के लिए धन्यवाद।

+0

... या सूची के बजाय varargs। –

उत्तर

5

यदि संसाधन कैलकुलेटर के जीवनकाल के लिए समान रहते हैं: संसाधनों को कैलकुलेटर के निर्माता को पास करें।

ResourceA resourceA = getResourceA(); 
ResourceB resourceB = getResourceB(); 

CostContainer costContainer = new CostContainer(); 

CostCalculator aCostCalculator = new ACostCalculator(); 
CostCalculator bCostCalculator = new BCostCalculator(); 
CostCalculator cCostCalculator = new CCostCalculator(resourceA); 
CostCalculator dCostCalculator = new DCostCalculator(resourceA); 
CostCalculator eCostCalculator = new ECostCalculator(resourceA, resourceB); 

aCostCalculator.calculate(costContainer); 
bCostCalculator.calculate(costContainer); 
cCostCalculator.calculate(costContainer); 
dCostCalculator.calculate(costContainer); 
eCostCalculator.calculate(costContainer); 
+1

यह अब तक का एकमात्र प्रकार-सुरक्षित समाधान है। और यहां तक ​​कि यदि तर्क कैलकुलेटर के जीवनकाल में स्थिर नहीं हैं, तो आप एक रैपर वर्ग का उपयोग कर एक समान तंत्र को लागू कर सकते हैं। –

+0

अच्छा, यह मेरे उपयोग के मामले को फ़िट करते समय पूरी तरह से मान्य और साफ दिखता है। –

+0

यह पहले से ही काफी सुंदर और सरल है। लेकिन चलो देखते हैं कि कोई अन्य प्रतिभा का जवाब दे सकता है –

0

आप variadic arguments उपयोग कर सकते हैं:

public interface CostCalculatorInterface { 
    public void calculate(CostContainer container, Object... resources); 
} 

(या ResourceA और ResourceB का एक और सुपर क्लास के साथ Object बदलें)।

कक्षाएं इंटरफेस को लागू करने में, resources एक Object[] ताकि आप के रूप में resources[0], resources[1] और इतने पर उन्हें का उल्लेख कर सकते हो जाएगा।

+2

हालांकि टाइप-सुरक्षित नहीं है ... –

+0

यदि आप संसाधनों की गलत संख्या पास करते हैं तो अपवाद को – ka4eli

+0

फेंक दिया जा सकता है। टाइप-सेफ एक समस्या है और पठनीयता के लिए भी है। एक और प्रोग्रामर को "संसाधन [0]" क्या पता लगाने के लिए कुछ प्रयास करने की आवश्यकता हो सकती है। –

-1

यह कुछ ऐसा है कि आप वास्तव में जेनेरिक्स के साथ उपयोग करते हैं:

Resource resourceA = new ResourceA(); 
    Resource resourceB = new ResourceB(); 
    CostContainer costContainer = new CostContainer(); 
    CostCalculator<Resource> costCalculatorA = new ACostCalculator(); 
    costCalculatorA.calculate(costContainer,resourceA,resourceB); 
    CostCalculator<Resource> costCalculatorB = new BCostCalculator(); 
    costCalculatorB.calculate(costContainer,resourceA); 


interface Resource { 
    //Your code 
} 

class ResourceA implements Resource { 
    //Your code 
} 

class ResourceB implements Resource { 
    //Your code 
} 

class CostContainer { 
    //Your code 
} 

interface CostCalculator<T extends Resource> { 
    void calculate(CostContainer costContainer, T... resources); 
} 

class ACostCalculator implements CostCalculator<Resource>{ 

    @Override 
    public void calculate(CostContainer costContainer, Resource... resources) { 
     System.out.println("Test"); 
    } 
} 

class BCostCalculator implements CostCalculator<Resource>{ 

    @Override 
    public void calculate(CostContainer costContainer, Resource... resources) { 
     System.out.println("Test2"); 
    } 
} 
+0

उत्तर देने के लिए धन्यवाद। हालांकि ग्लोफिंडेल के जवाब के समान ही त्रुटियां हैं। –

2

एक आम इंटरफेस के लिए हस्ताक्षर अलग की समस्या समस्या की तरह एक बहुत लग रहा है कि Adapter design pattern (object adapter variant) का हल:

Adapter pattern (GoF)

आपकी स्थिति के लिए लागू, आप केवल गैर-अनुरूप कैलकुलेटर के लिए एडाप्टर का उपयोग करेंगे। वास्तव में केवल दो प्रकार के एडेप्टर हैं, हस्ताक्षर (costContainer, resourceA) के लिए टाइप 1 और हस्ताक्षर (costContainer, resourceA, resourceB) के लिए टाइप 2 हैं। अपने उदाहरण का उपयोग करना:

Adapter pattern applied to your example

एडाप्टर के लाभ कर रहे हैं कि यह एक ज्ञात डिजाइन पैटर्न (1995 में GOF द्वारा प्रकाशित) है, यह अंतिम calculate(...) तरीकों है कि हस्ताक्षर अलग अनुमति देता है। संदर्भ परिवर्तन होने पर एडाप्टर को गतिशील रूप से अपडेट किया जा सकता है (उदा। संसाधनों में परिवर्तन)।

नुकसान स्पष्ट रूप से अतिरिक्त कक्षाएं, संकेतक इत्यादि हैं। यह चयनित उत्तर से अधिक जटिल है, लेकिन अधिक लचीला है, खासकर यदि आप एडैप्टेस के एपीआई को संशोधित नहीं कर सकते हैं।

+0

आपके उत्तर के लिए धन्यवाद। Lesmana से जवाब काम नहीं करते हैं अगर संसाधन और लागत कैलक्यूलेटर का जीवन चक्र मेल नहीं खाता है, उदाहरण के लिए लागत कैलिलेटर एक सिंगलटन है। एडाप्टर पैटर्न सभी परिस्थितियों में लागू कर सकते हैं? मुझे लगता है हाँ (माना जाता है कि लागत कैलक्यूलेटर थ्रेड सुरक्षित है)? –

+0

@ माइकल डब्ल्यू। पैटर्न हमेशा हल करने के उद्देश्य से समस्या के स्तर पर सामान्य समाधान होते हैं। इसे कोड पर लागू करना निश्चित रूप से जानने का एकमात्र तरीका है। ग्राहक कोड वास्तव में केवल एडाप्टर देखता है। जब तक वे तुरंत चालू और प्रबंधित होते हैं, तो इससे कोई फर्क नहीं पड़ता कि एडेप्टेस सिंगलेट हैं या नहीं। यदि आप गतिशील रूप से एडाप्टर के संदर्भ को बदलने की आवश्यकता है, तो आप उदा।, 'SetResourceA()' जोड़ सकते हैं। पैटर्न केवल आपको एक मानक इंटरफ़ेस प्रदान करता है। आपको बाकी (बदसूरत) विवरणों का ख्याल रखना होगा। – Fuhrmanator

+0

इसे धन्यवाद के साथ मिला। मुझे इसे बाद में आज़माएं। –

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

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