विरासत - superclasses में super.equals () का उपयोग करना जो सुपरक्लास के बराबर उपयोग की जाने वाली विधियों को ओवरराइड करता है

मैं एक कोड का परीक्षण कर रहा हूं और किसी समस्या पर ठोकर खा रहा हूं: क्या आपको super.equals() विधि को उपclass में कॉल करना चाहिए जो equals() में उपयोग की जाने वाली कुछ विधियों को ओवरराइड कर सकता है। सुपर क्लास की विधि?

आइए निम्नलिखित कोड पर विचार करें:

public abstract class Item {
    private int id;
    private float price;

    public Item(int id, String name, float price, String category) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.category = category;
    }

    public int getID() {
        return id;
    }

    public float getPrice() {
        return price;
    }

    @Override
    public boolean equals(Object object){
        if(object instanceof Item){
            Item item = (Item) object;
            if( id == item.getID()
                && price == item.getPrice())                    
            { return true; }
        }
        return false;
    }
}

और सबक्लास डिस्काउंट इटिम:

public class DiscountedItem extends Item {
   //discount stored in %
    private int discount;

    @Override
    public boolean equals(Object object) {
        if(object instanceof DiscountedItem){
            DiscountedItem item = (DiscountedItem) object;
            return (super.equals(item)
                    && discount == item.getDiscount()
            );
        }
        return false;
    }

    public int getDiscount() {
        return discount;
    }

    @Override
    public float getPrice() {
        return super.getPrice()*(100 - discount);
    }    
}

मैं बस एंजेलिका लैंगर के बराबर के रहस्यों को फिर से पढ़ रहा हूं() , जहां वह कहती है:

ऑब्जेक्ट के अलावा क्लास में सुपरक्लास होने पर super.equals() को असाइन किया जाना चाहिए।

लेकिन मुझे लगता है कि यह सब अप्रत्याशित है जब सबक्लास कुछ तरीकों को ओवरराइड करेगा। उदाहरण के लिए जब मैं बराबर का उपयोग करके 2 DiscountedItem ऑब्जेक्ट्स की तुलना करता हूं, तो सुपर विधि को कॉल किया जाता है और item.getPrice() गतिशील रूप से उपclass डिस्काउंट इटिम में सही विधि पर प्रेषित किया जाता है , जबकि अन्य मूल्य मान सीधे चर का उपयोग कर उपयोग किया जाता है।

तो, क्या यह वास्तव में मेरे ऊपर है (क्योंकि मुझे विधि को सही तरीके से कार्यान्वित करना चाहिए) या इसके आसपास कोई रास्ता है?

0
@Affe ओह यह एक असली वेब एप्लिकेशन भी नहीं है, यह सॉफ्टवेयर परीक्षण वर्ग में दिया गया एक अकादमिक उदाहरण है :) लेकिन मुझे नहीं लगता कि यह त्रुटि उद्देश्य पर बनाई गई थी ..
जोड़ा लेखक Kuba Spatny, स्रोत
कोई तर्क दे सकता है कि यहां रूट समस्या एक बीन गेटर में व्यावसायिक तर्क एम्बेड कर रही है, और अधिक अकादमिक प्रश्न नहीं पूछा :)
जोड़ा लेखक Affe, स्रोत
आपका उप-वर्ग ' बराबर विधि को इस तरीके से कार्यान्वित किया जाना चाहिए जो उस विधि के अनुबंध के अनुरूप है। super.equals() को प्रतिनिधि करने का कारण यह है कि बाल वर्ग शायद माता-पिता के फ़ील्ड तक नहीं पहुंच सकता है कि super.equals() पर निर्भर हो सकता है। यदि आप encapsulation का उल्लंघन करते हैं, तो सभी दांव बंद हैं। यदि आप अपने माता-पिता के अनुबंध को तोड़ने के लिए बाल वर्ग को सक्षम करके अपने super.equals() को खराब तरीके से कार्यान्वित करते हैं, तो फिर, सभी शर्त बंद हैं।
जोड़ा लेखक Floegipoky, स्रोत
यह प्रासंगिक है
जोड़ा लेखक Floegipoky, स्रोत

4 उत्तर

यदि आप डिस्काउंट इटिम के बराबर कहते हैं तो आपको कोई समस्या हो सकती है? अगर कुछ डिस्काउंट किया गया है और कुछ और आइटम है बराबर के बराबर बराबर नहीं हैं। सही? तो अगर आप एक समस्या नहीं देखते हैं हमेशा गेटर्स को बुलाओ।

इसके अलावा, यदि आप बराबर ओवरराइड करते हैं तो आपको हैशकोड को ओवरराइड करने की आवश्यकता है।

0
जोड़ा
ठीक है, हाँ, मेरा मुद्दा यह था कि ये "वस्तुओं के कुछ हिस्सों" हमेशा "वंश वर्ग से वस्तुओं के कुछ हिस्सों" होते हैं, इसलिए मैं कह रहा था कि मुझे इसके साथ कोई समस्या नहीं है (ओवरराइडिंग विधियों के संबंध में)।
जोड़ा लेखक peter.petrov, स्रोत
मैं विभिन्न वस्तुओं की तुलना करने की कोशिश नहीं कर रहा हूं, लेकिन उन वस्तुओं के हिस्सों की तुलना करें जो उनके माता-पिता से निहित थे। हैशकोड लागू किया गया है, लेकिन मैंने इसे शामिल नहीं किया क्योंकि इसमें समस्या से कोई लेना देना नहीं है ..
जोड़ा लेखक Kuba Spatny, स्रोत

ओह, मुझे लगता है कि मुझे इसे पाने के लिए सिर्फ प्रश्न पोस्ट करना पड़ा ..

समस्या से छुटकारा पाने के लिए, सीधे चरों तक पहुंचने के बजाय - गेटर्स को कॉल करें!

@Override
public boolean equals(Object object){
      if(object instanceof Item){
          Item item = (Item) object;
          if( this.getID() == item.getID()
              && this.getPrice() == item.getPrice())                    
          { return true; }
      }
      return false;
}

विधियों को ओवरराइड करते समय इस कोड में अब समस्या नहीं है।

0
जोड़ा
@ मैट हर। एक। पहर। लेकिन हे, तुमने मुझे मार दिया ..
जोड़ा लेखक Kuba Spatny, स्रोत
ऐसा नहीं है कि यह हमेशा कैसे काम करता है। बहुत बढ़िया।
जोड़ा लेखक Matt, स्रोत

इंस्टेंस वैरिएबल की तुलना अपने संबंधित गेटर विधि से तुलना करने के बजाय सीधे इंस्टेंस चर की तुलना करें।

उदाहरण के लिए, बदलें

&& price == item.getPrice())

सेवा मेरे

&& this.price == item.price)

गेटटर विधि अनावश्यक है क्योंकि निजी आवृत्ति चर वर्ग संरचना के बाहर केवल पहुंच योग्य नहीं हैं।


नोट:

मैंने पहले निम्नलिखित की सिफारिश की थी:

&& this.getPrice() == item.getPrice())

हालांकि यह प्रश्न के उदाहरण में काम करेगा, यह सभी मामलों के लिए उपयुक्त नहीं है। इस बात पर विचार करें कि उपclass DiscountedItem ने विधि getPrice को इस तरह घोषित किया है:

@Override
public float getPrice() {
    return Math.floor(super.getPrice());
} 

इसके परिणामस्वरूप झूठी समकक्षता होगी:

DiscountedItem firstItem = DiscountedItem(1, "", 1.1, "");
DiscountedItem secondItem = DiscountedItem(1, "", 1.0, "");
firstItem.equals(secondItem);//Returns true despite different prices.
0
जोड़ा
मैं @ फ्लोगोपीकी से सहमत हूं। कक्षा के सदस्य चर की तुलना सीधे गेटटर विधियों के परिणाम की तुलना में की तुलना की जानी चाहिए। जब उनके चर वैल्यू बराबर नहीं होते हैं तब भी उनकी विधियों की तुलना करते समय दो ऑब्जेक्ट बराबर हो सकते हैं। मैं तदनुसार अपना जवाब अपडेट करूंगा।
जोड़ा लेखक Matt, स्रोत

बराबर का कार्यान्वयन राज्य और प्रकार पर निर्भर होना चाहिए, लेकिन कार्यक्षमता नहीं। आप अपनी बेस क्लास में गलत हो गए:

@Override
public boolean equals(Object object){
    if(object instanceof Item){//Type check- good!
        Item item = (Item) object;
        if( id == item.getID() //Depends on functionality- bad!
            && price == item.getPrice())//Depends on functionality- bad!                    
        { return true; }
    }
    return false;
}

item.getID() and item.getPrice(), as you've noticed, can be overwritten to break the contract of Item.equals().

@Override
public boolean equals(Object object){
    if(object instanceof Item){//Type check- good!
        Item item = (Item) object;
        if( id == item.id //Depends on state- good!
            && price == item.price) //Depends on state- good!
        { return true; }
    }
    return false;
}

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

@Override
public boolean equals(Object object) {
    if(object instanceof DiscountedItem){
        DiscountedItem item = (DiscountedItem) object;
        return (super.equals(item)
                && this.discount == item.discount
        );
    }
    return false;
}

बच्चे को केवल उस डेटा की तुलना करने की चिंता करने की ज़रूरत है जो उसके पास है।

0
जोड़ा
इस उत्तर के लिए धन्यवाद, आप बिल्कुल सही हैं! आम तौर पर, जब मैं कोड लिखता हूं तो मैं ऐसा करता हूं जैसा कि आप सुझाव देते हैं, हालांकि मुझे नहीं पता था कि यह अब तक कितना गलत हो सकता है .. लेकिन सिर्फ रिकॉर्ड के लिए, मैंने यह कोड नहीं लिखा, मुझे बस इसका परीक्षण करना था । फिर से धन्यवाद!
जोड़ा लेखक Kuba Spatny, स्रोत