क्या "चाइल्ड x = न्यू चाइल्ड ()?" के बजाय "पेरेंट x = न्यू चाइल्ड ()?" एक बुरा अभ्यास है अगर हम बाद वाले का उपयोग कर सकते हैं?


32

उदाहरण के लिए, मैंने कुछ कोड देखे थे जो इस तरह एक टुकड़ा बनाते हैं:

Fragment myFragment=new MyFragment();

जो MyFragment के बजाय Fragment के रूप में एक चर घोषित करता है, जो MyFragment Fragment का एक बच्चा वर्ग है। मुझे लगता है कि कोड की इस लाइन पर मुझे कोई भरोसा नहीं है क्योंकि मुझे लगता है कि यह कोड होना चाहिए:

MyFragment myFragment=new MyFragment();

जो अधिक विशिष्ट है, क्या यह सच है?

या प्रश्न के सामान्यीकरण में, क्या इसका उपयोग करना बुरा है:

Parent x=new Child();

के बजाय

Child x=new Child();

यदि हम संकलन त्रुटि के बिना पूर्व एक को बाद में बदल सकते हैं?


6
यदि हम उत्तरार्द्ध करते हैं, तो अब अमूर्तन / सामान्यीकरण का कोई मतलब नहीं है। बेशक अपवाद हैं ...
वॉलफ्रैट

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

4
@Walfrat वास्तव में एब्स्ट्रैक्शन का कोई मतलब नहीं है जब आप पहले से ही कंक्रीट टाइप कर रहे हों, लेकिन आप एब्सट्रैक्ट टाइप को वापस कर सकते हैं ताकि क्लाइंट कोड आनंदित हो।
जैकब रायल

4
माता-पिता / बच्चे का उपयोग न करें। इंटरफ़ेस / क्लास (जावा के लिए) का उपयोग करें।
Thorbjørn रावन एंडरसन

4
Google "इंटरफ़ेस के लिए प्रोग्रामिंग" स्पष्टीकरण के एक समूह के लिए क्यों का उपयोग Parent x = new Child()करना एक अच्छा विचार है।
केविन वर्कमैन

जवाबों:


69

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

एक उदाहरण एक होगा LinkedListऔर ArrayListजो दोनों से उतरते हैं List। यदि कोड किसी भी प्रकार की सूची के साथ समान रूप से अच्छी तरह से काम करेगा, तो उपवर्गों में से किसी को भी इसे प्रतिबंधित करने का कोई कारण नहीं है।


24
ठीक ठीक। एक उदाहरण जोड़ने के लिए, इस बारे में सोचें कि List list = new ArrayList()सूची का उपयोग करने वाले कोड को परवाह नहीं है कि यह किस प्रकार की सूची है, केवल वह सूची इंटरफ़ेस के अनुबंध से मिलती है। भविष्य में, हम आसानी से एक अलग सूची कार्यान्वयन में बदल सकते हैं और अंतर्निहित कोड को बिल्कुल बदलने या अपडेट करने की आवश्यकता नहीं होगी।
है_फैक्टर

19
अच्छा जवाब लेकिन इसका विस्तार करना चाहिए कि सबसे सार प्रकार संभव है इसका मतलब है कि कुछ बच्चे विशिष्ट ऑपरेशन करने के लिए कोड को दायरे में वापस बच्चे को नहीं डालना चाहिए।
माइक

10
@ माइक: मुझे उम्मीद है कि बिना कहे चले जाएंगे, अन्यथा सभी चर, पैरामीटर और क्षेत्र घोषित किए जाएंगे Object!
जैक्सबी

3
@JacquesB: इस सवाल और जवाब के बाद से मुझे इतना ध्यान मिला कि मैं सोच रहा था कि स्पष्ट होना सभी विभिन्न कौशल स्तरों वाले लोगों के लिए उपयोगी होगा।
माइक

1
यह संदर्भ पर निर्भर करता है एक उत्तर नहीं है।
बिलाल बेगुएरदज

11

जैक्सबी का उत्तर सही है, हालांकि थोड़ा सार। मुझे कुछ पहलुओं पर अधिक स्पष्ट रूप से जोर देने दें:

आपके कोड स्निपेट में, आप स्पष्ट रूप से newकीवर्ड का उपयोग करते हैं , और शायद आप आगे के प्रारंभिक चरणों के साथ जारी रखना चाहेंगे, जो कंक्रीट प्रकार के लिए विशिष्ट हैं: फिर आपको उस विशिष्ट कंक्रीट प्रकार के साथ चर को घोषित करने की आवश्यकता है।

जब आप उस वस्तु को कहीं और से प्राप्त करते हैं, तो स्थिति अलग होती है, जैसे IFragment fragment = SomeFactory.GiveMeFragments(...);। यहां, कारखाने को आम तौर पर सबसे सार प्रकार को वापस करना चाहिए, और डाउनवर्ड कोड कार्यान्वयन विवरण पर निर्भर नहीं होना चाहिए।


18
"हालांकि थोड़ा सार"। Badumtish।
रसुव

1
क्या यह एक संपादन नहीं हो सकता था?
beppe9000

6

संभावित प्रदर्शन अंतर हैं।

यदि व्युत्पन्न वर्ग को सील कर दिया जाता है, तो कंपाइलर इनलाइन कर सकता है और अनुकूलन कर सकता है या समाप्त कर सकता है अन्यथा वर्चुअल कॉल हो सकता है। तो एक महत्वपूर्ण प्रदर्शन अंतर हो सकता है।

उदाहरण: ToStringएक आभासी कॉल है, लेकिन Stringसील है। पर String, ToStringएक नो-ऑप है, इसलिए यदि आप घोषित करते हैं objectकि यह एक वर्चुअल कॉल है, तो यदि आप घोषणा करते हैं Stringकि कंपाइलर जानता है कि किसी व्युत्पन्न वर्ग ने विधि को ओवरराइड नहीं किया है क्योंकि क्लास सील है, इसलिए यह एक नो-ऑप है। इसी तरह के विचार ArrayListबनाम पर लागू होते हैं LinkedList

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


4
ज्यादातर मामलों में, प्रदर्शन मतभेद माइनसक्यूल होते हैं। और ज्यादातर मामलों में (मैंने सुना है कि यह समय का लगभग 90% है) हमें उन छोटे अंतरों के बारे में भूलना चाहिए। केवल जब हम जानते हैं (अधिमानतः माप के माध्यम से) कि हम प्रदर्शन कोड के महत्वपूर्ण खंड के रूप में उम्र में हम इस तरह के अनुकूलन के बारे में ध्यान रखना चाहिए।
जूल्स

और संकलक जानता है कि "नया बच्चा ()" एक बच्चे को देता है, यहां तक ​​कि जब वह माता-पिता को सौंपा जाता है, और जब तक यह जानता है, वह उस ज्ञान का उपयोग कर सकता है और बाल () कोड को कॉल कर सकता है।
gnasher729 18

+1। मेरे उत्तर में अपना उदाहरण चुरा लिया। = पी
नट

1
ध्यान दें कि प्रदर्शन ऑप्टिमाइज़ेशन हैं जो पूरी चीज़ को मूट बनाते हैं। उदाहरण के लिए हॉटस्पॉट यह नोटिस करेगा कि एक फ़ंक्शन के लिए दिया गया पैरामीटर हमेशा एक विशिष्ट वर्ग का होता है और तदनुसार अनुकूलित होता है। अगर वह धारणा कभी झूठी हो जाए तो विधि को गलत माना जाता है। लेकिन यह दृढ़ता से कंपाइलर / रनटाइम वातावरण पर निर्भर करता है। पिछली बार मैंने CLR भी से कि पी देख के बजाय तुच्छ अनुकूलन नहीं कर सका जाँच की Parent p = new Child()हमेशा एक बच्चा है ..
Voo

4

मुख्य अंतर आवश्यक पहुंच का स्तर है। और अमूर्तता के बारे में हर अच्छे उत्तर में जानवर शामिल हैं, या इसलिए मुझे बताया गया है।

मान लीजिए कि आपके पास कुछ जानवर हैं - Cat Birdऔर Dog। अब, इन जानवरों में कुछ सामान्य व्यवहार है - move(), eat(), और speak()। वे सभी अलग-अलग खाते हैं और अलग तरह से बोलते हैं, लेकिन अगर मुझे अपने जानवर को खाने या बोलने की ज़रूरत है तो मुझे वास्तव में परवाह नहीं है कि वे इसे कैसे करते हैं।

लेकिन कभी-कभी करता हूं। मैंने कभी भी गार्ड की बिल्ली या गार्ड बर्ड की मेहनत नहीं की है, लेकिन मेरे पास एक गार्ड डॉग है। इसलिए जब कोई मेरे घर में घुसता है, तो मैं घुसपैठिये को डराने के लिए सिर्फ बोलने पर भरोसा नहीं कर सकता। मुझे वास्तव में अपने कुत्ते को भौंकने की ज़रूरत है - यह उसकी बात से अलग है, जो सिर्फ एक वाह है।

तो कोड में एक घुसपैठिए की आवश्यकता है जो मुझे वास्तव में करने की आवश्यकता है Dog fido = getDog(); fido.barkMenancingly();

लेकिन ज्यादातर समय, मैं खुशी से किसी भी जानवर को कर सकता हूं जहां वे व्यवहार करते हैं, म्याऊ या ट्वीट करते हैं। Animal pet = getAnimal(); pet.speak();

तो अधिक ठोस होने के लिए, ArrayList में कुछ विधियाँ हैं जो Listनहीं करती हैं। विशेष रूप से, trimToSize()। अब, 99% मामलों में, हम इस बारे में परवाह नहीं करते हैं। Listलगभग कभी बड़ा पर्याप्त देखभाल करने के लिए हमें के लिए है। लेकिन कई बार ऐसा होता है। तो कभी कभी, हम विशेष रूप से एक के लिए पूछना चाहिए ArrayListनिष्पादित करने के लिए trimToSize()और उसके समर्थन सरणी छोटा करने के।

ध्यान दें कि यह निर्माण पर नहीं होना चाहिए - यह एक वापसी विधि या यहां तक ​​कि एक कास्ट के माध्यम से किया जा सकता है अगर हम बिल्कुल निश्चित हैं।


उलझन में है कि यह एक गिरावट क्यों हो सकती है। यह व्यक्तिगत रूप से विहित लगता है। एक प्रोग्राम योग्य गार्ड कुत्ते के विचार को छोड़कर ...
corsiKa

मुझे सर्वश्रेष्ठ उत्तर प्राप्त करने के लिए, पृष्ठों को क्यों पढ़ना पड़ा? रेटिंग बेकार है।
बसिलेव्स

आपके नम्र शब्दों के लिए धन्यवाद। रेटिंग सिस्टम के लिए पेशेवरों और विपक्ष हैं, और उनमें से एक यह है कि बाद के उत्तर कभी-कभी धूल में छोड़ सकते हैं। होता है!
corsiKa

2

सामान्यतया, आपको उपयोग करना चाहिए

var x = new Child(); // C#

या

auto x = new Child(); // C++

स्थानीय चर के लिए जब तक कि चर के लिए एक अच्छा कारण न हो जैसा कि इसके साथ आरंभ किया जाता है।

(यहां मैं इस तथ्य को नजरअंदाज कर रहा हूं कि C ++ कोड को स्मार्ट पॉइंटर का उपयोग करने की सबसे अधिक संभावना होनी चाहिए। ऐसे मामले हैं जो एक पंक्ति में नहीं हैं और जिनके बिना मैं वास्तव में नहीं जान सकता हूं।)

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


1
C ++ में, चर ज्यादातर नए कीवर्ड के बिना बनाए जाते हैं: stackoverflow.com/questions/6500313/…
Marian Spanik

1
यह सवाल C # / C ++ के बारे में नहीं है, बल्कि एक सामान्य वस्तु उन्मुख मुद्दे के बारे में है जिसमें भाषा में कम से कम कुछ स्टैटिक टाइपिंग है (यानी, यह रूबी की तरह कुछ पूछना निरर्थक होगा)। इसके अलावा, यहां तक ​​कि उन दो भाषाओं में, मैं वास्तव में एक अच्छा कारण नहीं देखता हूं कि हमें ऐसा क्यों करना चाहिए जैसा आप कहते हैं।
AoE

1

अच्छा है क्योंकि इसे समझना आसान है और इस कोड को संशोधित करना आसान है:

var x = new Child(); 
x.DoSomething();

अच्छा है क्योंकि यह इरादे का संचार करता है:

Parent x = new Child(); 
x.DoSomething(); 

ठीक है, क्योंकि यह आम और समझने में आसान है:

Child x = new Child(); 
x.DoSomething(); 

एक विकल्प जो वास्तव में बुरा है, Parentयदि केवल Childएक विधि का उपयोग करना है DoSomething()। यह बुरा है क्योंकि यह गलत तरीके से इरादे का संचार करता है:

Parent x = new Child(); 
(x as Child).DoSomething(); // DON'T DO THIS! IF YOU WANT x AS CHILD, STORE x AS CHILD

अब इस मामले पर थोड़ा और विस्तार से पूछें जो विशेष रूप से सवाल पूछता है:

Parent x = new Child(); 
x.DoSomething(); 

दूसरी छमाही फ़ंक्शन कॉल करके इसे अलग तरीके से प्रारूपित करें:

WhichType x = new Child(); 
FunctionCall(x);

void FunctionCall(WhichType x)
    x.DoSomething(); 

इसे छोटा किया जा सकता है:

FunctionCall(new Child());

void FunctionCall(WhichType x)
    x.DoSomething();

यहाँ, मुझे लगता है कि यह व्यापक रूप से स्वीकृत है जो WhichTypeसबसे बुनियादी / सार प्रकार होना चाहिए जो फ़ंक्शन को काम करने की अनुमति देता है (जब तक कि प्रदर्शन चिंताएं न हों)। इस मामले में उचित प्रकार Parentया तो होगा , या कुछ से Parentप्राप्त होता है।

तर्क की यह पंक्ति बताती है कि प्रकार Parentका उपयोग करना एक अच्छा विकल्प क्यों है, लेकिन यह मौसम में नहीं जाता है अन्य विकल्प खराब हैं (वे नहीं हैं)।


1

tl; dr -Child ओवरParentका उपयोग करनास्थानीय दायरे में बेहतर है। यह न केवल पठनीयता में मदद करता है, बल्कि यह सुनिश्चित करने के लिए भी आवश्यक है कि अतिभारित विधि संकल्प ठीक से काम करता है और कुशल संकलन को सक्षम करने में मदद करता है।


स्थानीय दायरे में,

Parent obj = new Child();  // Works
Child  obj = new Child();  // Better
var    obj = new Child();  // Best

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

पूर्ण प्रकार की जानकारी को पुनः प्राप्त करने के चार मुख्य लाभ हैं:

  1. संकलक को अधिक जानकारी प्रदान करता है।
  2. पाठक को अधिक जानकारी प्रदान करता है।
  3. क्लीनर, अधिक मानकीकृत कोड।
  4. प्रोग्राम लॉजिक को अधिक म्यूट करता है।

लाभ 1: संकलक को अधिक जानकारी

स्पष्ट प्रकार का उपयोग अतिभारित विधि संकल्प और अनुकूलन में किया जाता है।

उदाहरण: अतिभारित विधि संकल्प

main()
{
    Parent parent = new Child();
    foo(parent);

    Child  child  = new Child();
    foo(child);
}
foo(Parent arg) { /* ... */ }  // More general
foo(Child  arg) { /* ... */ }  // Case-specific optimizations

उपरोक्त उदाहरण में, दोनों foo()कॉल काम करते हैं , लेकिन एक मामले में, हम बेहतर अधिभार विधि संकल्प प्राप्त करते हैं।

उदाहरण: संकलक अनुकूलन

main()
{
    Parent parent = new Child();
    var x = parent.Foo();

    Child  child  = new Child();
    var y = child .Foo();
}
class Parent
{
    virtual         int Foo() { return 1; }
}
class Child : Parent
{
    sealed override int Foo() { return 2; }
}

उपरोक्त उदाहरण में, दोनों .Foo()कॉल अंततः उसी overrideविधि को कहते हैं जो वापस आती है 2। बस, पहले मामले में, सही विधि खोजने के लिए एक आभासी विधि लुकअप है; इस विधि के बाद से दूसरे मामले में इस वर्चुअल मेथड लुकअप की आवश्यकता नहीं है sealed

@Ben को श्रेय जिन्होंने अपने जवाब में एक समान उदाहरण दिया

फायदा 2: पाठक को अधिक जानकारी

सटीक प्रकार को जानना, अर्थात Child, जो कोई भी कोड पढ़ रहा है, उसे अधिक जानकारी प्रदान करता है, जिससे यह देखना आसान हो जाता है कि कार्यक्रम क्या कर रहा है।

ज़रूर, शायद यह वास्तविक कोड से कोई फर्क नहीं पड़ता है parent.Foo();और दोनों के बाद सेchild.Foo(); समझ में आता है, लेकिन किसी के लिए पहली बार कोड देखकर, अधिक जानकारी का सिर्फ सादा मददगार।

इसके अतिरिक्त, आपके विकास के वातावरण के आधार पर, IDE इससे अधिक उपयोगी टूलटिप और मेटाडेटा प्रदान करने में सक्षम हो सकता ChildहैParent

लाभ 3: क्लीनर, अधिक मानकीकृत कोड

अधिकांश C # कोड उदाहरण जिन्हें मैंने हाल ही में देखा है var, जो मूल रूप से शॉर्टहैंड हैं Child

Parent obj = new Child();  // Sub-optimal
Child  obj = new Child();  // Optimal, but anti-pattern syntax
var    obj = new Child();  // Optimal, clean, patterned syntax "everyone" uses now

एक गैर- varघोषणा बयान को देखने से सिर्फ यह दिखता है; अगर इसके लिए एक स्थितिजन्य कारण है, भयानक, लेकिन अन्यथा यह विरोधी पैटर्न दिखता है।

// Clean:
var foo1 = new Person();
var foo2 = new Job();
var foo3 = new Residence();

// Staggered:
Person foo1 = new Person();
Job foo2 = new Job();
Residence foo3 = new Residence();   

लाभ 4: प्रोटोटाइपिंग के लिए अधिक परस्पर प्रोग्राम लॉजिक

पहले तीन फायदे बड़े वाले थे; यह बहुत अधिक स्थितिजन्य है।

फिर भी, जो लोग दूसरों की तरह कोड का उपयोग करते हैं, वे एक्सेल का उपयोग करते हैं, हम लगातार अपना कोड बदल रहे हैं। हो सकता है कि हमें कोड के इस संस्करण Childमें अद्वितीय तरीके से कॉल करने की आवश्यकता न हो, लेकिन हम बाद में कोड को फिर से तैयार कर सकते हैं या फिर से काम कर सकते हैं।

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

सारांश

Parentओवरलोड विधि विधि से गड़बड़ी का उपयोग करना , कुछ संकलक अनुकूलन को रोकता है, पाठक से जानकारी को हटाता है, और कोड को कुरूप बनाता है।

उपयोग करना varवास्तव में जाने का मार्ग है। यह त्वरित, स्वच्छ, प्रतिरूपित है, और कंपाइलर और IDE को अपना काम ठीक से करने में मदद करता है।


महत्वपूर्ण : यह उत्तरएक विधि के स्थानीय दायरेमेंParentबनाम केबारेChildमें है। ParentबनामChildकामुद्दावापसी के प्रकारों, तर्कों और वर्ग क्षेत्रों के लिए बहुत अलग है।


2
मुझे लगता Parent list = new Child()है कि ज्यादा मतलब नहीं है जोड़ देगा। वह कोड जो सीधे किसी वस्तु का ठोस उदाहरण बनाता है (जैसा कि कारखानों, फैक्ट्री विधियों आदि के माध्यम से अप्रत्यक्ष रूप से विरोध किया जाता है) में बनाई गई प्रकार के बारे में सही जानकारी होती है, इसे नए बनाए गए ऑब्जेक्ट को कॉन्फ़िगर करने के लिए कंक्रीट इंटरफ़ेस के साथ बातचीत करने की आवश्यकता हो सकती है आदि। स्थानीय स्कोप वह नहीं है जहाँ आप लचीलापन प्राप्त करें। लचीलेपन को प्राप्त किया जाता है जब आप उस वर्ग के एक नए ग्राहक के लिए एक अधिक अमूर्त इंटरफ़ेस (कारखानों और कारखाने के तरीकों का एक आदर्श उदाहरण हैं) का उपयोग करते हुए उजागर करते हैं
crizzis

"tl; डॉ। चाइल्ड ओवर पेरेंट का उपयोग करना स्थानीय दायरे में बेहतर है। यह न केवल पठनीयता में मदद करता है," - जरूरी नहीं ... यदि आप बच्चे की बारीकियों का कोई उपयोग नहीं करते हैं, तो यह केवल आवश्यक से अधिक विवरण जोड़ देगा। "लेकिन यह सुनिश्चित करने के लिए भी आवश्यक है कि अतिभारित विधि संकल्प ठीक से काम करता है और कुशल संकलन को सक्षम करने में मदद करता है।" - जो प्रोग्रामिंग भाषा पर बहुत कुछ निर्भर करता है। बहुत सारे हैं जिनके पास इससे कोई मुद्दा नहीं है।
14

1
क्या आपके पास एक ऐसा स्रोत है Parent p = new Child(); p.doSomething();और जिसका Child c = new Child; c.doSomething();व्यवहार अलग है? हो सकता है कि यह किसी भाषा में एक विचित्रता है, लेकिन यह माना जाता है कि वस्तु व्यवहार को नियंत्रित करती है, संदर्भ को नहीं। यही विरासत की खूबसूरती है! जब तक आप जाने के लिए अच्छे माता-पिता के कार्यान्वयन के अनुबंध को पूरा करने के लिए बच्चे के कार्यान्वयन पर भरोसा कर सकते हैं।
corsiKa

@corsiKa हाँ, यह कुछ तरीकों से संभव है। दो त्वरित उदाहरण होंगे जहां विधि हस्ताक्षर अधिलेखित हैं, उदाहरण के लिए newC # में कीवर्ड के साथ , और जब C ++ में कई-वंशानुक्रम के साथ कई परिभाषाएं हैं, जैसे ।
नट

@corsiKa बस एक त्वरित तीसरा उदाहरण है (क्योंकि मुझे लगता है कि यह सी ++ और सी # के बीच एक साफ विपरीत है), सी # में सी + + की तरह एक मुद्दा है, जहां आप स्पष्ट-इंटरफ़ेस विधियों से भी इस व्यवहार को प्राप्त कर सकते हैं । यह मजाकिया है क्योंकि इन मुद्दों से बचने के लिए C # जैसी इंटरफेस मल्टीपल-इनहेरिटेंस-इन-पार्ट के बजाय इंटरफेस का उपयोग करते हैं, लेकिन इंटरफेस को अपनाने से, वे अभी भी मुद्दे का हिस्सा बन गए हैं - लेकिन, यह काफी बुरा नहीं है क्योंकि, इस परिदृश्य में, यह केवल लागू होता है जब करने के लिए Parentहै एक interface
नेट

0

यह देखते हुए parentType foo = new childType1();, कोड माता-पिता-प्रकार के तरीकों का उपयोग करने के लिए सीमित होगा foo, लेकिन fooकिसी भी ऑब्जेक्ट के संदर्भ में स्टोर करने में सक्षम होगा, जिसका प्रकार parentकेवल उदाहरण से नहीं निकलता है childType1। यदि नया childType1उदाहरण ही एक ऐसी चीज है, जो fooकभी भी एक संदर्भ रखेगा, तो बेहतर होगा कि इसका fooप्रकार घोषित किया जाए childType1। दूसरी ओर, यदि fooअन्य प्रकार के संदर्भों को रखने की आवश्यकता हो सकती है , तो यह घोषित किया जाना parentTypeसंभव होगा।


0

मैं उपयोग करने का सुझाव देता हूं

Child x = new Child();

के बजाय

Parent x = new Child();

उत्तरार्द्ध जानकारी खो देता है जबकि पूर्व नहीं करता है।

आप पूर्व के साथ सब कुछ कर सकते हैं जो आप बाद के साथ कर सकते हैं लेकिन इसके विपरीत नहीं।


सूचक को और विस्तृत करने के लिए, आइए आपके पास विरासत के कई स्तर हैं।

Base-> DerivedL1->DerivedL2

और आप new DerivedL2()एक चर के परिणाम को इनिशियलाइज़ करना चाहते हैं । आधार प्रकार का उपयोग करना आपको उपयोग करने का विकल्प छोड़ देता है BaseयाDerivedL1

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

Base x = new DerivedL2();

या

DerivedL1 x = new DerivedL2();

मैं किसी भी तार्किक तरीके से एक दूसरे को पसंद नहीं करता।

यदि तुम प्रयोग करते हो

DerivedL2 x = new DerivedL2();

इसके बारे में बहस करने के लिए कुछ भी नहीं है।


3
कम करने में सक्षम होने के नाते यदि आपको अधिक करने की आवश्यकता नहीं है तो यह एक अच्छी बात है, नहीं?
पीटर

1
@ पेटर, कम करने की क्षमता विवश नहीं है। यह हमेशा संभव है। यदि अधिक करने की क्षमता विवश है, तो यह एक पीड़ादायक बिंदु हो सकता है।
आर साहू

लेकिन जानकारी खोना कभी-कभी अच्छी बात होती है। आपको पदानुक्रम के बारे में बताते हुए, ज्यादातर लोग शायद Base(यह काम करता है) के लिए वोट करेंगे । आप सबसे विशिष्ट पसंद करते हैं, AFAIK बहुमत कम से कम विशिष्ट पसंद करता है। मैं कहूंगा कि स्थानीय चर के लिए यह शायद ही मायने रखता है।
मआर्टिनस

@maaartinus, मुझे आश्चर्य है कि अधिकांश उपयोगकर्ता जानकारी खोना पसंद करते हैं। मैं जानकारी खोने के लाभों को उतना स्पष्ट रूप से नहीं देख रहा हूं जितना कि अन्य हैं।
आर साहू

जब आप घोषणा करते हैं Base x = new DerivedL2();तो आप सबसे अधिक विवश होते हैं और यह आपको न्यूनतम प्रयास के साथ एक और (भव्य) बच्चे को बदलने की अनुमति देता है। इसके अलावा, आप तुरंत देखते हैं कि यह संभव है। +++ क्या हम सहमत हैं कि इससे void f(Base)बेहतर है void f(DerivedL2)?
मातरिनस

0

मैं हमेशा चर को सबसे विशिष्ट प्रकार के रूप में लौटाने या संग्रहीत करने का सुझाव दूंगा, लेकिन मापदंडों को व्यापक प्रकार के रूप में स्वीकार करना।

उदाहरण के लिए

<K, V> LinkedHashMap<K, V> keyValuePairsToMap(List<K> keys, List<V> values) {
   //...
}

पैरामीटर List<T>, एक बहुत ही सामान्य प्रकार हैं। ArrayList<T>,LinkedList<T> और अन्य सभी को इस विधि द्वारा स्वीकार किया जा सकता है।

महत्वपूर्ण रूप से, वापसी प्रकार है LinkedHashMap<K, V>, नहीं Map<K, V>। यदि कोई इस विधि के परिणाम को असाइन करना चाहता है aMap<K, V> , तो वे ऐसा कर सकते हैं। यह स्पष्ट रूप से बताता है कि यह परिणाम सिर्फ एक नक्शे से अधिक है, लेकिन एक परिभाषित आदेश के साथ एक नक्शा।

मान लीजिए यह तरीका वापस आ गया Map<K, V>। यदि कॉल करने वाला व्यक्ति चाहता था LinkedHashMap<K, V>, तो उन्हें एक प्रकार की जाँच, कास्ट और एरर हैंडलिंग करनी होगी, जो वास्तव में बोझिल है।


एक ही तर्क जो आपको एक व्यापक प्रकार को एक पैरामीटर के रूप में स्वीकार करने के लिए मजबूर करता है, साथ ही रिटर्न प्रकार पर भी लागू होना चाहिए। यदि फ़ंक्शन का लक्ष्य मानों के लिए कुंजी मैप करना है, तो इसे वापस Mapनहीं लौटना चाहिए LinkedHashMap- आप केवल LinkedHashMapएक फ़ंक्शन keyValuePairsToFifoMapया जैसे कुछ के लिए वापस लौटना चाहेंगे । व्यापक तब तक बेहतर है जब तक आपके पास एक विशिष्ट कारण नहीं है।
corsiKa

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

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

दरअसल, मैं अंतिम वाक्य तक सभी तरह से सहमत हूं। आप से बदल LinkedHashMapकरने के लिए TreeMapइस तरह के से बदल रहा है के रूप में, एक छोटी सी परिवर्तन नहीं है ArrayListकरने के लिए LinkedList। यह शब्दार्थ महत्व वाला परिवर्तन है। उस स्थिति में आप चाहते हैं कि कंपाइलर एक त्रुटि फेंकने के लिए, बदले मूल्य के उपभोक्ताओं को परिवर्तन को नोटिस करने और उचित कार्रवाई करने के लिए मजबूर करे।
अलेक्जेंडर -

लेकिन यह एक तुच्छ परिवर्तन हो सकता है यदि आप सभी के बारे में परवाह करते हैं तो मानचित्र व्यवहार (जो, यदि आप कर सकते हैं, तो आपको करना चाहिए।) यदि अनुबंध "आपको एक महत्वपूर्ण मूल्य का नक्शा मिलेगा" और आदेश कोई फर्क नहीं पड़ता (जो कि इसके लिए सही है) अधिकांश नक्शे) तो यह कोई फर्क नहीं पड़ता कि यह एक पेड़ या हैश नक्शा है। उदाहरण के लिए, Thread#getAllStackTraces()- सड़क के नीचे Map<Thread,StackTraceElement[]>एक HashMapविशेष रूप से एक के बजाय रिटर्न ताकि वे इसे जो Mapचाहें टाइप कर सकें ।
corsiKa
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.