2012-10-02 15 views
5

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

तो, हम तरीकों में से एक टन है doSomethingWithAFruit (फल च) और doSomethingWithAVegetable (शाकाहारी v), कि का उपयोग उचित doOtherStuffWithAFruit (फल च)/doOtherStuffWithAVeg (शाकाहारी v)। और वे बहुत समान हैं, उन तरीकों को छोड़कर जो फल के साथ चीजें करते हैं केवल उन तरीकों को बुलाते हैं जो फल के साथ चीजें करते हैं, और सब्जियों के लिए एक ही चीज़ है।

मैं डुप्लिकेशंस को कम करने के लिए इसे पुन: सक्रिय करना चाहता हूं, लेकिन मुझे यकीन नहीं है कि इसे पूरा करने का सबसे अच्छा तरीका क्या है। मैंने कुछ डिज़ाइन पैटर्न के बारे में कुछ पढ़ा है, लेकिन मुझे नहीं पता कि यह मेरे लिए कोई स्पष्ट है या नहीं। (मैं अपने द्वारा उपयोग किए जाने वाले कोड में कुछ पैटर्न पहचान सकता हूं, लेकिन मुझे वास्तव में पता नहीं है कि मुझे चीजों को बेहतर बनाने के लिए एक पैटर्न लागू करना चाहिए। शायद मुझे खुद को रिफैक्टर करने के बारे में और अधिक पढ़ना चाहिए ...)

मैं था इन दो विकल्पों के बारे में सोच:

1. एक ऐसी कक्षा बनाना जिसमें फल या सब्जियों का उदाहरण हो और इसे डुप्लिकेशंस को कम करने की कोशिश कर रहे तरीकों तक पहुंच जाए। यह इस तरह होगा:

public void doSomething(Plant p) { 
    // do the stuff that is common, and then... 
    if (p.hasFruit()) { 
     doThingWithFruit(p.getFruit()); 
    } else { 
     doThingWithVegetable(p.getVegetable()); 
    } 
} 

इससे चीजें थोड़ा बेहतर हो जाएंगी, लेकिन मुझे नहीं पता ... यह अभी भी गलत लगता है।

2. दूसरा विकल्प मैंने सोचा था कि फलों और सब्जियों में उनके लिए आम चीजों के साथ एक इंटरफेस डालना था, और इसे पारित करने के लिए इसका उपयोग करना था। मुझे लगता है कि यह क्लीनर दृष्टिकोण है, हालांकि मुझे instanceof का उपयोग करना होगा और फल/सब्जी के लिए डालना होगा जब उन्हें उन चीजों की आवश्यकता होती है जो उनके लिए विशिष्ट हैं।

तो, मैं यहां और क्या कर सकता हूं? और इन दृष्टिकोणों की कमी क्या हैं?

अद्यतन: ध्यान दें कि प्रश्न थोड़ा सा सरल है, मैं "पौधों" के साथ चीजों को करने का तरीका ढूंढ रहा हूं, यानी कोड, जो उन्हें चीजों को करने के बजाए अधिकतर "उपयोग" करता है। करने के बाद कहा कि, उन समान तरीकों मैं उल्लेख करने के लिए "संयंत्रों" वर्गों के अंदर नहीं किया जा सकता, और वे आमतौर पर एक और तर्क है, जैसे:

public void createSomethingUsingFruit(Something s, Fruit f); 
public void createSomethingUsingVegetable(Something s, Vegetable v); 

अर्थात् उन तरीकों के अलावा फल/सब्जियों में अन्य चिंताएं हैं, और 'नहीं कर रहे वास्तव में किसी भी फल/सब्जी वर्ग में होने के लिए विनियमित नहीं है।

अद्यतन 2: उन तरीकों में अधिकांश कोड केवल फल/सब्जी वस्तुओं से राज्य पढ़ता है, और अन्य वर्गों के उदाहरण, डेटाबेस में इतने पर उचित प्रकार के अनुसार बनाने की दुकान और - करने के लिए अपने जवाब से टिप्पणियों में एक सवाल है कि मुझे लगता है कि यह महत्वपूर्ण है

+0

क्या होगा यदि पौधे फल या सब्जी नहीं है? –

+0

मुझे लगता है कि आपको एक सामान्य इंटरफ़ेस की ओर बढ़ने का सही विचार है। संग्रह पर भी पढ़ें। संभवतया प्रकार की एक श्रेणी बनाएं जो किसी भी तरीके, ऑब्जेक्ट्स, वैरिएबल को परिभाषित करने के लिए आपको के रूप में लचीला होने की आवश्यकता है और फिर अपने मुख्य/रनटाइम में उस कंक्रीट को बनाना। –

+0

यदि आप दोनों के लिए सामान्य कार्यों को लागू कर सकते हैं (आपके द्वारा उल्लिखित डुप्लिकेट के आधार पर मानते हुए), तो अमूर्त वर्ग का उपयोग करना बेहतर है क्योंकि आप इसे कक्षा में कार्यान्वित कर सकते हैं जो निश्चित रूप से सबक्लास पर डुप्लिकेट कोड को कम करेगा। – Jimmy

उत्तर

1

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

उदाहरण के लिए, अपने उपभोक्ता कहा जाता है, तो खाओ, आप की तरह कुछ करना होगा:

Consumer e = new Eat(); 
Consumer w = new Water(); 
if(e.canProcess(myFruit)) 
    e.doSomethingWith(myFruit); 
else if (w.canProcess(myFruit)) 
    w.doSomethingWith(myFruit); 

.... etc 

लेकिन तब आप इसके बारे में एक बहुत कुछ के साथ खत्म हो/किसी और कक्षाएं, ताकि आप अपने आप एक फैक्टरी जो निर्धारित करता है कि कौन उपभोक्ता आप चाहते हैं। आपकी फैक्ट्री मूल रूप से यह निर्धारित करने के लिए शाखा बनाती है कि कौन सा उपभोक्ता आपके द्वारा पारित ऑब्जेक्ट को संभाल सकता है, और उपभोक्ता को आपके पास वापस कर देता है।

Consumer c = Factory.getConsumer(myFruit); 
c.doSomethingWith(myFruit); 
उपभोक्ता की canProcess विधि में बेशक

, यह मूल रूप से एक instanceof या कुछ अन्य समारोह अपने निकाले जाते हैं होगा:

तो यह

public class Factory { 
    public static Consumer getConsumer(Object o){ 
    Consumer e = new Eat(); 
    Consumer w = new Water(); 
    if(e.canProcess(o)) 
     return e; 
    else if (w.canProcess(o)) 
     return w; 
    } 
} 

की तरह कुछ फिर अपने कोड हो जाता है लग रहा है यह निर्धारित करने के लिए कि क्या यह आपकी कक्षा को संभाल सकता है।

public class Eat implements Consumer{ 
    public boolean canProcess(Object o){ 
    return o instanceof Fruit; 
    } 
} 

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

मुझे एहसास है कि मेरा छद्म कोड बहुत बुनियादी है, लेकिन यह सामान्य विचार को इंगित करने के लिए है। यह आपके मामले में काम कर सकता है या नहीं हो सकता है और/या आपकी कक्षाओं को कैसे संरचित किया जाता है, इस पर निर्भर करता है, लेकिन यदि अच्छी तरह से डिज़ाइन किया गया है, तो आपके कोड की पठनीयता में काफी सुधार हो सकता है, और अपने स्वयं के वर्ग में प्रत्येक प्रकार के स्वयं निहित सभी तर्कों को सचमुच रख सकता है उदाहरण के बिना और अगर/तो हर जगह बिखरे हुए।

+0

हाय! ऐसा करने के तरीकों के लिए ऐसा करने के लिए यह बहुत अधिक होगा, लेकिन मैं शायद एक ऐसी जगह ढूंढने जा रहा हूं जहां मुझे अच्छा अलगाव पाने के लिए कुछ चाहिए। आपका बहुत बहुत धन्यवाद! – elias

2

मुझे लगता है कि दूसरा दृष्टिकोण बेहतर होगा .. एक इंटरफ़ेस को डिज़ाइन करना हमेशा डिजाइन करने का एक बेहतर तरीका है .. इस तरह आप आसानी से अपने कार्यान्वयन के बीच स्विच कर सकते हैं ..

और अगर आप इंटरफेस का उपयोग करें, आप .. यही है, आप `एक उपवर्ग वस्तु के लिए आधार वर्ग संदर्भ इशारा होगा समान किरदार करने के लिए के रूप में आप आसानी से polymorphism की अवधारणा दोहन कर सकते हैं की जरूरत नहीं होगी ..

लेकिन आप केवल तरीकों आम fruits और अपने इंटरफेस में vegetables, और अपने कार्यान्वयन कक्षा में विशिष्ट कार्यान्वयन के लिए .. उस मामले typecasting की आवश्यकता होगी में तो रखने के लिए फिर ..

चाहते हैं तो आपको इंटरफेस पर एक सामान्य विधि हो सकता है स्तर .. और कार्यान्वयन स्तर पर अधिक विशिष्ट विधि ..

public interface Food { 
    public void eat(Food food); 
} 

public class Fruit implements Food { 

    // Can have interface reference as parameter.. But will take Fruit object  
    public void eat(Food food) { 
     /** Fruit specific task **/ 
    } 
} 

public class Vegetable implements Food { 

    // Can have interface reference as parameter.. But will take Vegetable object 
    public void eat(Food food) { 
     /** Vegetable specific task **/ 
    } 
} 

public class Test { 
    public static void main(String args[]) { 
     Food fruit = new Fruit(); 
     fruit.eat(new Fruit()); // Invoke Fruit Version 

     Food vegetable = new Vegetable(); 
     vegetable.eat(new Vegetable()); // Invoke vegetable version 

    } 
} 

ठीक है, मैं प्रकार Food के मापदंडों लेने के लिए .. यही कारण है कि बहुत अधिक अंतर नहीं पड़ेगा eat() विधि बनाने के लिए एक संशोधित किया है .. आप Vegetable वस्तु Food संदर्भ के लिए पारित कर सकते हैं ..

+0

+1 मैं 'फूड' और 'डूसमिंग' को इंटरफेस 'इटेबल' और विधि 'इटरेटर() ' –

+1

@ पीटर लेवरी के नाम से संबंधित नाम बनाने की कोशिश करूंगा .. हाहा :) सुझाव के लिए धन्यवाद .. संपादित कोड .. अब यह अच्छा लग रहा है :) –

+0

हाय!बात यह है कि, विधियों में कोड वास्तव में फल या सब्जी के बारे में चिंतित नहीं हैं। मैंने अपना प्रश्न अधिक स्पष्ट होने की कोशिश कर अद्यतन किया है। वैसे भी आपके ध्यान के लिए धन्यवाद! :) – elias

0

मैं करूंगा निर्माण और सार आधार वर्ग (मान लें - भोजन, लेकिन मुझे आपके डोमेन को नहीं पता, कुछ और बेहतर हो सकता है) और दूसरे के बाद विधियों को माइग्रेट करना प्रारंभ करें।

यदि आप देखते हैं कि 'doSomethingWithVeg' और 'doSomthingWithFruit' थोड़ा अलग हैं - बेस क्लास पर 'doSomething' विधि बनाएं और केवल अलग-अलग हिस्सों को करने के लिए अमूर्त विधियों का उपयोग करें (मुझे लगता है कि मुख्य व्यवसाय तर्क कर सकता है एकजुट हो जाएं, और डीबी/फाइल को लिखने जैसे छोटे मामूली मुद्दे अलग हैं)।

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

उम्मीद है कि यह मदद करता है ..

0

यह एक मूल ओओडी प्रश्न है। चूंकि फल और सब्जियां प्रकार के पौधे हैं। मेरा सुझाव है:

interface Plant { 
    doSomething(); 
} 

class Vegetable { 
    doSomething(){ 
    .... 
    } 
} 

और फल के साथ एक ही।

ऐसा लगता है कि DoOtherStuff विधियों को प्रासंगिक वर्ग के लिए निजी होना चाहिए।

0

आप दोनों को केवल एक के बजाय कई इंटरफेस लागू करने पर विचार कर सकते हैं। इस तरह आप उन परिस्थितियों के अनुसार सबसे सार्थक इंटरफेस के खिलाफ कोड करते हैं जो कास्टिंग से बचने में मदद करेंगे। Comparable<T> क्या करता है। यह विधियों (जैसे ऑब्जेक्ट्स को सॉर्ट करने वाले) की मदद करता है, जहां वे परवाह नहीं करते हैं कि ऑब्जेक्ट्स क्या हैं, केवल आवश्यकता यह है कि उन्हें तुलनीय होना चाहिए। जैसे आपके मामले में दोनों Edible नामक कुछ इंटरफेस को कार्यान्वित कर सकते हैं, फिर उन दोनों को Edible के रूप में ले जाएं जहां Edible अपेक्षित है।

1

यदि आपके पास कार्यक्षमता है जो क्रमशः फल और सब्जियों के लिए विशिष्ट है और दोनों प्रकार का उपयोग करने वाले क्लाइंट को अलग करना है (instanceof का उपयोग करके) - यह एक समेकन बनाम युग्मन समस्या है।

शायद यह मानें कि क्या कार्यक्षमता क्लाइंट के बजाय फल और सब्जियों के पास बेहतर नहीं है। क्लाइंट को किसी भी तरह कार्यक्षमता (एक सामान्य इंटरफ़ेस के माध्यम से) में फिर से पेश किया जा सकता है, यह ध्यान में रखते हुए कि वह किस उदाहरण से निपट रहा है। पॉलिमॉर्फिज्म कम से कम ग्राहक के परिप्रेक्ष्य से संरक्षित किया जाएगा।

लेकिन यह सैद्धांतिक है और व्यावहारिक नहीं हो सकता है या आपके उपयोग के मामले में अधिक इंजीनियर नहीं हो सकता है। या आप वास्तव में अपने डिजाइन में कहीं और instanceof छुपा सकते हैं। instanceof एक बुरी चीज होने जा रहा है जब आप फल और सब्जियों के बगल में अधिक विरासत भाई बहन शुरू करते हैं। फिर आप Open Closed Principle का उल्लंघन करना शुरू कर देंगे।

+0

हम्म ... धन्यवाद, बहुत ही उचित उत्तर। मेरे मामले में, यह निश्चित है कि कोई अन्य भाई नहीं होगा। मैं सिर्फ सामान को पुनर्गठित करने की कोशिश कर रहा हूं। मुझे लगता है कि मैं अभी भी अपने पहले विकल्प के साथ जा रहा हूं। – elias

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