अशक्त मूल्य के साथ विरासत बनाम अतिरिक्त संपत्ति


12

वैकल्पिक फ़ील्ड वाले वर्गों के लिए, विरासत या अशक्त संपत्ति का उपयोग करना बेहतर है? इस उदाहरण पर विचार करें:

class Book {
    private String name;
}
class BookWithColor extends Book {
    private String color;
}

या

class Book {
    private String name;
    private String color; 
    //when this is null then it is "Book" otherwise "BookWithColor"
}

या

class Book {
    private String name;
    private Optional<String> color;
    //when isPresent() is false it is "Book" otherwise "BookWithColor"
}

इन 3 विकल्पों के आधार पर कोड होगा:

if (book instanceof BookWithColor) { ((BookWithColor)book).getColor(); }

या

if (book.getColor() != null) { book.getColor(); }

या

if (book.getColor().isPresent()) { book.getColor(); }

पहला दृष्टिकोण मेरे लिए अधिक स्वाभाविक लगता है, लेकिन शायद कास्टिंग करने की आवश्यकता के कारण यह कम पठनीय है। क्या इस व्यवहार को प्राप्त करने का कोई और तरीका है?


1
मुझे डर है कि समाधान आपके व्यापार नियमों की परिभाषा में आता है। मेरा मतलब है, अगर आपकी सभी पुस्तकों में रंग हो सकता है, लेकिन रंग वैकल्पिक है, तो वंशानुक्रम ओवरकिल है और वास्तव में अनावश्यक है, क्योंकि आप चाहते हैं कि आपकी सभी पुस्तकें यह जान सकें कि रंग संपत्ति मौजूद है। दूसरी ओर, यदि आपके पास दोनों किताबें हो सकती हैं, जो रंग के बारे में कुछ नहीं जानती हैं तो क्या हुआ और जिन किताबों में रंग है, विशेष कक्षाएं बनाना बुरा नहीं है। फिर भी, मैं शायद विरासत पर रचना के लिए जाऊंगा।
एंडी

इसे थोड़ा और विशिष्ट बनाने के लिए - 2 प्रकार की किताबें हैं - एक रंग के साथ और एक बिना। इसलिए सभी पुस्तकों में रंग नहीं हो सकता है।
बोजान वकासोविचटेस्ट

1
यदि वास्तव में कोई ऐसा मामला है, जहां पुस्तक में रंग बिल्कुल भी नहीं है, तो आपके मामले में विरासत एक रंगीन किताब के गुणों को बढ़ाने का सबसे सरल तरीका है। इस मामले में ऐसा नहीं लगता है कि आप बेस बुक क्लास को इनहेरिट करके और उसमें कलर प्रॉपर्टी जोड़कर कुछ भी तोड़ रहे होंगे। जब आप किसी वर्ग के विस्तार की अनुमति देते हैं और जब ऐसा नहीं होता है तो आप मामलों के बारे में अधिक जानने के लिए लिस्कोव प्रतिस्थापन सिद्धांत के बारे में पढ़ सकते हैं।
एंडी

4
क्या आप एक ऐसे व्यवहार की पहचान कर सकते हैं जिसे आप रंगों से पुस्तकों से चाहते हैं? क्या आप रंगों के साथ और बिना किताबों के बीच एक सामान्य व्यवहार पा सकते हैं, जहां रंगों वाली पुस्तकों को थोड़ा अलग ढंग से व्यवहार करना चाहिए? यदि हां, तो यह ओओपी के लिए विभिन्न प्रकारों के साथ एक अच्छा मामला है, और, विचार यह होगा कि संपत्ति की उपस्थिति और मूल्य को बाहरी रूप से पूछताछ करने के बजाय कक्षाओं में व्यवहार को स्थानांतरित करें।
एरिक Eidt

1
यदि पुस्तक के संभावित रंगों को समय से पहले जाना जाता है, तो BookColor.NCColor के विकल्प के साथ BookColor के लिए Enum फ़ील्ड के बारे में कैसे?
ग्राहम

जवाबों:


7

यह परिस्थितियों पर निर्भर करता है। विशिष्ट उदाहरण अवास्तविक है क्योंकि आपके पास BookWithColorएक वास्तविक कार्यक्रम में बुलाया उपवर्ग नहीं होगा ।

लेकिन सामान्य तौर पर, एक संपत्ति जो केवल कुछ उपवर्गों के लिए समझ में आती है, केवल उन उपवर्गों में मौजूद होनी चाहिए।

उदाहरण के लिए यदि Bookहै PhysicalBookऔर DigialBookवंशज के रूप में, तो PhysicalBookएक हो सकता है weightसंपत्ति, और DigitalBookएक sizeInKbसंपत्ति। लेकिन DigitalBookनहीं होगा weightऔर इसके विपरीत। Bookकोई संपत्ति नहीं होगी, क्योंकि एक वर्ग के पास केवल सभी वंशजों द्वारा साझा किए गए गुण होने चाहिए।

एक बेहतर उदाहरण वास्तविक सॉफ्टवेयर से कक्षाएं देख रहा है। JSliderघटक क्षेत्र है majorTickSpacing। चूंकि केवल एक स्लाइडर में "टिक" होता है, इसलिए यह फ़ील्ड केवल JSliderऔर उसके वंश के लिए समझ में आता है । यह बहुत भ्रामक होगा यदि अन्य भाई जैसे घटकों के JButtonपास कोई majorTickSpacingक्षेत्र हो।


या आप दोनों को प्रतिबिंबित करने में सक्षम होने के लिए वजन कम कर सकते हैं, लेकिन यह शायद बहुत अधिक है।
वॉलफ्रैट

3
@Walfrat: एक ही क्षेत्र के विभिन्न उपवर्गों में पूरी तरह से अलग चीजों का प्रतिनिधित्व करना वास्तव में एक बुरा विचार होगा।
जैक्सबी

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

@ 4castle: आपको प्रति संस्करण अलग वर्गों की आवश्यकता होगी, क्योंकि प्रत्येक संस्करण की अलग-अलग कीमत भी हो सकती है। आप इसे वैकल्पिक क्षेत्रों के साथ हल नहीं कर सकते। लेकिन हम उदाहरण से नहीं जानते हैं कि अगर ऑप रंग या "रंगहीन पुस्तकों" के साथ पुस्तकों के लिए अलग व्यवहार चाहता है, तो यह जानना असंभव है कि इस मामले में सही मॉडलिंग क्या है।
जैक्सबी

3
@JacquesB से सहमत हैं। आप "मॉडलिंग पुस्तकों" के लिए एक सार्वभौमिक रूप से सही समाधान नहीं दे सकते हैं, क्योंकि यह इस बात पर निर्भर करता है कि आप किस समस्या को हल करने की कोशिश कर रहे हैं और आपका व्यवसाय क्या है। मुझे लगता है कि यह कहना बहुत सुरक्षित है कि वर्ग पदानुक्रम को परिभाषित करना जहां आप लिज़कोव का उल्लंघन करते हैं, स्पष्ट रूप से गलत है (टीएम) हालांकि (हाँ, हाँ, आपका मामला संभवतः बहुत विशेष है और यह वारंट करता है (हालांकि मुझे संदेह है))
सारा

5

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

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


यह वास्तव में एक महत्वपूर्ण बिंदु है! यह परिभाषित करता है कि क्या किसी को वर्ग गुणों के बजाय वैकल्पिक गुणों के संग्रह पर विचार करना चाहिए।
क्रोमैनॉइड

1

Bookएक डेटाबेस में एक रिकॉर्ड के रूप में एक जावाबीन (अपने जैसे ) के बारे में सोचो । वैकल्पिक स्तंभ nullतब होते हैं जब उनका कोई मूल्य नहीं होता है, लेकिन यह पूरी तरह से कानूनी है। इसलिए, आपका दूसरा विकल्प:

class Book {
    private String name;
    private String color; // null when not applicable
}

सबसे उचित है। 1

यद्यपि आप Optionalकक्षा का उपयोग कैसे करते हैं, इसके साथ सावधान रहें । उदाहरण के लिए, यह नहीं है Serializable, जो आमतौर पर एक जावाबीन की विशेषता है। यहाँ स्टीफन कोलबोर्न के कुछ सुझाव दिए गए हैं :

  1. किसी भी प्रकार के चर को घोषित न करें Optional
  2. nullएक वर्ग के निजी दायरे के भीतर वैकल्पिक डेटा को इंगित करने के लिए उपयोग करें ।
  3. Optionalवैकल्पिक फ़ील्ड तक पहुँचने वाले गेटर्स के लिए उपयोग करें ।
  4. Optionalसेटर या कंस्ट्रक्टर में उपयोग न करें ।
  5. Optionalवैकल्पिक परिणाम वाले किसी भी अन्य व्यावसायिक तर्क विधियों के लिए वापसी प्रकार के रूप में उपयोग करें ।

इसलिए, के भीतर अपने वर्ग का उपयोग करना चाहिए nullप्रतिनिधित्व करने के लिए उस क्षेत्र में मौजूद नहीं है, लेकिन जब color पत्तेBook (एक वापसी प्रकार के रूप में) यह एक साथ लिपटे किया जाना चाहिए Optional

return Optional.ofNullable(color); // inside the class

book.getColor().orElse("No color"); // outside the class

यह स्पष्ट डिजाइन और अधिक पठनीय कोड प्रदान करता है।


1 यदि आप BookWithColorकिताबों की एक पूरी "क्लास" को एनकैप्सुलेट करने का इरादा रखते हैं, जिसमें अन्य पुस्तकों की विशेष क्षमताएं हैं, तो यह विरासत का उपयोग करने के लिए समझ में आता है।


1
डेटाबेस के बारे में कुछ भी किसने कहा? यदि सभी OO पैटर्न को एक रिलेशनल डेटाबेस प्रतिमान में फिट होना था, तो हमें बहुत सारे OO पैटर्न बदलने होंगे।
एलेक्जेंडरबर्ड

मैं अप्रयुक्त गुणों को जोड़ने का तर्क दूंगा "बस के मामले में" कम से कम स्पष्ट विकल्प है। जैसा कि दूसरों ने कहा, यह उपयोग के मामले पर निर्भर करता है, लेकिन सबसे वांछनीय स्थिति उन संपत्तियों के आसपास नहीं होगी जहां बाहरी अनुप्रयोग को यह जानना होगा कि मौजूद संपत्ति वास्तव में उपयोग की जा रही है या नहीं।
वोल्कर क्यूफेल

@ वोलर चलो असहमत होने के लिए सहमत हैं, क्योंकि मैं ऐसे कई लोगों का हवाला दे सकता हूं जिन्होंने Optionalइस सटीक उद्देश्य के लिए जावा में कक्षा को जोड़ने में हाथ खेला । यह OO नहीं हो सकता है, लेकिन यह निश्चित रूप से एक मान्य राय है।
4castle

@Alexanderbird मैं विशेष रूप से एक जावाबीन से निपट रहा था, जिसे क्रमबद्ध होना चाहिए। अगर मैं JavaBeans को लाकर विषय से दूर था, तो वह मेरी गलती थी।
4castle

@Alexanderbird मैं एक संबंधपरक डेटाबेस से मेल खाने के लिए सभी पैटर्न की उम्मीद नहीं करता, लेकिन मुझे जावा बीन की उम्मीद है
4castle

0

आपको या तो एक इंटरफ़ेस (इनहेरिटेंस नहीं) या किसी प्रकार की संपत्ति मैकेनिक का उपयोग करना चाहिए (शायद कुछ ऐसा भी हो जो संसाधन विवरण ढांचे की तरह काम करता है)।

तो या तो

interface Colored {
  Color getColor();
}
class ColoredBook extends Book implements Colored {
  ...
}

या

class PropertiesHolder {
  <T> extends Property<?>> Optional<T> getProperty( Class<T> propertyClass ) { ... }
  <V, T extends Property<V>> Optional<V> getPropertyValue( Class<T> propertyClass ) { ... }
}
interface Property<T> {
  String getName();
  T getValue();
}
class ColorProperty implements Property<Color> {
  public Color getValue() { ... }
  public String getName() { return "color"; }
}
class Book extends PropertiesHolder {
}

स्पष्टीकरण (संपादित करें):

बस इकाई वर्ग में वैकल्पिक क्षेत्रों को जोड़ना

विशेष रूप से वैकल्पिक आवरण के साथ (संपादित करें: देखें 4cast का जवाब) मुझे लगता है कि यह (मूल इकाई में फ़ील्ड को जोड़ना) एक छोटे पैमाने में नई संपत्तियों को जोड़ने का एक व्यवहार्य तरीका है। इस दृष्टिकोण के साथ सबसे बड़ी समस्या यह है कि यह कम युग्मन के खिलाफ काम कर सकता है।

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

जब अतिरिक्त गुण प्रदान करने का तरीका आता है तो वंशानुक्रम की समस्या क्यों होती है?

जब मैं आपका उदाहरण वर्ग "बुक" देखता हूं, तो मैं एक ऐसे डोमेन ऑब्जेक्ट के बारे में सोचता हूं जो अक्सर कई वैकल्पिक फ़ील्ड और उपप्रकार समाप्त करता है। बस कल्पना करें कि आप उन पुस्तकों के लिए एक संपत्ति जोड़ना चाहते हैं जिनमें एक सीडी शामिल है। अब चार तरह की किताबें हैं: किताबें, रंग वाली किताबें, सीडी वाली किताबें, रंग और सीडी वाली किताबें । आप जावा में इनहेरिटेंस के साथ इस स्थिति का वर्णन नहीं कर सकते।

इंटरफेस के साथ आप इस मुद्दे को दरकिनार करते हैं। आप आसानी से इंटरफेस के साथ एक विशिष्ट पुस्तक वर्ग के गुणों की रचना कर सकते हैं। प्रतिनिधिमंडल और रचना से आप जिस कक्षा को चाहते हैं, ठीक उसी तरह से प्राप्त करना आसान हो जाएगा। वंशानुक्रम के साथ आप आमतौर पर कक्षा में कुछ वैकल्पिक गुणों के साथ समाप्त होते हैं जो केवल इसलिए होते हैं क्योंकि एक सहोदर वर्ग को उनकी आवश्यकता होती है।

आगे पढ़ने क्यों विरासत अक्सर एक समस्याग्रस्त विचार है:

वंशानुक्रम को आमतौर पर ओओपी समर्थकों द्वारा एक बुरी बात के रूप में क्यों देखा जाता है

JavaWorld: क्यों फैली बुराई है

गुणों का एक सेट बनाने के लिए इंटरफेस के एक सेट को लागू करने के साथ समस्या

जब आप विस्तार के लिए इंटरफेस का उपयोग करते हैं तो सब कुछ ठीक है जब तक कि आपके पास उनमें से बस एक छोटा सा सेट है। खासतौर पर तब जब आपकी कंपनी में आपके डेवलपर मॉडल का उपयोग और विस्तार किया जाता है, जैसे आपकी कंपनी में इंटरफेस की मात्रा बढ़ेगी। और अंत में आप एक नया आधिकारिक "प्रॉपर्टी-इंटरफ़ेस" बनाते हैं, जो आपके सहयोगियों द्वारा पहले से ही ग्राहक के एक्स के लिए एक पूरी तरह से असंबंधित उपयोग के मामले में एक विधि को जोड़ता है - ऊग।

संपादित करें: gnasher729 द्वारा एक और महत्वपूर्ण पहलू का उल्लेख किया गया है । आप अक्सर किसी मौजूदा ऑब्जेक्ट में वैकल्पिक रूप से वैकल्पिक गुण जोड़ना चाहते हैं। वंशानुक्रम या इंटरफेस के साथ आपको पूरी वस्तु को दूसरी कक्षा के साथ फिर से बनाना होगा जो कि वैकल्पिक से दूर है।

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

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


और यह सवाल "इन विकल्पों के बीच कैसे तय करें" को संबोधित नहीं किया है, यह सिर्फ एक और विकल्प है। ओपी द्वारा प्रस्तुत सभी विकल्पों की तुलना में यह हमेशा बेहतर क्यों है?
एलेक्जेंडरबर्ड

आप सही हैं, मैं जवाब में सुधार करूंगा।
गुणसूत्र

@ 4castle जावा इंटरफेस में इनहेरिटेंस नहीं हैं! इंटरफेस को लागू करना एक अनुबंध का पालन करने का एक तरीका है, जबकि एक वर्ग को विरासत में मूल रूप से अपने व्यवहार का विस्तार करना है। जब आप एक कक्षा में कई वर्गों का विस्तार नहीं कर सकते, तो आप कई इंटरफेस लागू कर सकते हैं। मेरे उदाहरण में आप मूल इकाई के व्यवहार को प्राप्त करने के लिए विरासत का उपयोग करते समय इंटरफेस के साथ विस्तार करते हैं।
क्रोमैनॉइड

समझ में आता है। आपके उदाहरण में, PropertiesHolderशायद एक अमूर्त वर्ग होगा। लेकिन आप क्या सुझाव देंगे कि यह एक कार्यान्वयन है getPropertyया getPropertyValue? डेटा को अभी भी किसी तरह के उदाहरण क्षेत्र में संग्रहीत किया जाना है। या आप Collection<Property>खेतों का उपयोग करने के बजाय गुणों को संग्रहीत करने के लिए एक का उपयोग करेंगे ?
4

1
मैंने स्पष्टता के कारणों का Bookविस्तार PropertiesHolderकिया। PropertiesHolderआमतौर पर सभी वर्गों इस कार्यक्षमता की जरूरत है कि में एक सदस्य होना चाहिए। कार्यान्वयन एक Map<Class<? extends Property<?>>,Property<?>>या कुछ इस तरह पकड़ होगा । यह कार्यान्वयन का बदसूरत हिस्सा है लेकिन यह वास्तव में एक अच्छा ढांचा प्रदान करता है जो JAXB और JPA के साथ भी काम करता है।
गुणसूत्र

-1

यदि Bookवर्ग नीचे की तरह रंग की संपत्ति के बिना व्युत्पन्न है

class E_Book extends Book{
   private String type;
}

तब उत्तराधिकार वाजिब है।


मुझे यकीन नहीं है कि मैं आपके उदाहरण को समझ सकता हूं? यदि colorनिजी है, तो किसी भी व्युत्पन्न वर्ग को किसी भी तरह से संबंधित नहीं होना चाहिए color। बस कुछ कंस्ट्रक्टरों को इसमें शामिल करें Bookजो colorपूरी तरह से नजरअंदाज करते हैं और यह डिफ़ॉल्ट होगा null
4
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.