उदाहरण के लिए जिस तरह से यह है निर्माण क्यों है?


17

मैंने पिछले छह महीनों में C # सीखा है और अब मैं जावा में डील कर रहा हूं। मेरा प्रश्न उदाहरण निर्माण (भाषा में, वास्तव में) के बारे में है और यह अधिक है: मुझे आश्चर्य है कि उन्होंने ऐसा क्यों किया। इसका उदाहरण लीजिए

Person Bob = new Person();

क्या कोई कारण है कि वस्तु दो बार निर्दिष्ट की जाती है? वहाँ एक कभी होगा something_else Bob = new Person()?

ऐसा लगता है कि अगर मैं सम्मेलन से आगे चल रहा हूं तो यह अधिक पसंद होगा:

int XIsAnInt;
Person BobIsAPerson;

या शायद इनमें से एक:

Person() Bob;
new Person Bob;
new Person() Bob;
Bob = new Person();

मुझे लगता है मैं उत्सुक हूँ अगर वहाँ से एक बेहतर जवाब है "कि बस जिस तरह से यह किया जाता है"।


26
क्या होगा यदि व्यक्ति का उप-प्रकार है LivingThing? आप लिख सकते हैं LivingThing lt = new Person()। के लिए देखो विरासत और इंटरफेस।
xlecoustillier

2
Person Bob"" के लिए " संदर्भ" प्रकार के एक चर की घोषणा करता है । एक वस्तु बनाता है । संदर्भ, चर और वस्तुएं तीन अलग-अलग चीजें हैं! PersonBobnew Person()Person
user253751

5
क्या आप अतिरेक से परेशान हैं? फिर क्यों नहीं लिखा var bob = new Person();?
२००

4
Person Bob();C ++ में संभव है और इसका मतलब लगभग वही हैPerson Bob = Person();
user60561

3
@ user60561 नहीं, यह बिना किसी तर्क के एक फ़ंक्शन की घोषणा करता है और व्यक्ति को वापस करता है।
निकोलाई

जवाबों:


52

क्या कभी कोई_बेल्स बॉब = नया व्यक्ति () होगा?

हां, विरासत की वजह से। अगर:

public class StackExchangeMember : Person {}

फिर:

Person bob = new StackExchangeMember();
Person sam = new Person();

बॉब एक ​​व्यक्ति भी है, और हंसमुख होकर, वह किसी और की तुलना में अलग व्यवहार नहीं करना चाहता है।

इसके अलावा, हम सुपर शक्तियों के साथ बॉब का समर्थन कर सकते हैं:

public interface IModerator { }
public class StackOverFlowModerator : StackExchangeMember, IModerator {}

IModerator bob = new StackOverFlowModerator();

और इसलिए, golly द्वारा, वह किसी भी अन्य मध्यस्थ की तुलना में किसी भी तरह का व्यवहार करने के लिए खड़ा नहीं होगा। और वह मंच के चारों ओर छीना-झपटी करना पसंद करता है ताकि हर कोई गुप्त हो सके:

StackExchangeMember bob = new StackOverFlowModerator();

फिर जब वह कुछ गरीब 1 पोस्टर पाता है, तो वह अदृश्यता के अपने लबादे को फेंक देता है और उछलता है।

((StackOverFlowModerator) bob).Smite(sam);

और फिर वह बाद में सभी निर्दोष और सामान कार्य कर सकता है:

((Person) bob).ImNotMeanIWasJustInstantiatedThatWay();

20
यदि आप अपने ऑब्जेक्ट नामों को कम करते हैं तो यह बहुत स्पष्ट होगा।
लाइटेनेस रेस मोनिका

38
विनिर्देश का अच्छा उदाहरण; विरासत का बुरा उदाहरण। इसे पढ़ने वाले किसी और के लिए, कृपया, वंशानुक्रम का उपयोग करके उपयोगकर्ता भूमिकाओं को हल करने का प्रयास न करें।
हारून

8
@ अचंभा सही है। विभिन्न प्रकार के लोगों के लिए अलग-अलग कक्षाएं न बनाएँ। एक बिटफील्ड का उपयोग करें enum
कोल जॉनसन

1
@Aaronaught यह सब बहुत अच्छी तरह से कह रहा है कि क्या नहीं करना है, लेकिन यह बिना यह कहे बहुत उपयोगी नहीं है कि लोगों को क्या करना चाहिए।
फाप्र्स

5
@ चित्र: मैंने कई अन्य प्रश्नों में ठीक यही किया है । इसका सरल उत्तर यह है कि उपयोगकर्ताओं (प्रमाणीकरण / पहचान) और सुरक्षा नीति (प्राधिकरण / अनुमति) को अलग-अलग चिंताओं के रूप में माना जाना चाहिए, और सुरक्षा नीति के मानक मॉडल या तो भूमिका-आधारित या दावे-आधारित हैं। वास्तव में प्रमाणीकरण करने वाली वस्तु का वर्णन करने के लिए विरासत अधिक उपयोगी है, उदाहरण के लिए एक LDAP कार्यान्वयन और एक SQL कार्यान्वयन।
हारून

34

आइए कोड की अपनी पहली पंक्ति लें और इसकी जांच करें।

Person Bob = new Person();

पहला Personएक प्रकार का विनिर्देश है। C # में, हम केवल यह कहकर इसे दूर कर सकते हैं

var Bob = new Person();

और कंपाइलर कंस्ट्रक्टर कॉल से चर बॉब के प्रकार का अनुमान लगाएगाPerson()

लेकिन आप कुछ इस तरह लिखना चाहते हैं:

IPerson Bob = new Person();

जहाँ आप व्यक्ति के संपूर्ण API अनुबंध को पूरा नहीं कर रहे हैं, लेकिन केवल इंटरफ़ेस द्वारा निर्दिष्ट अनुबंध IPerson


2
+1: मैं IPersonअपने कोड में उदाहरण दूंगा कि यह सुनिश्चित करने के लिए कि मैं किसी निजी तरीके का उपयोग नहीं करता हूं जब मैं कोड लिख रहा हूं जो किसी अन्य IPersonकार्यान्वयन के लिए कॉपी / पेस्ट करने योग्य होना चाहिए ।
Cort Ammon - मोनिका

@CortAmmon मुझे लगता है कि आपके पास वहां एक टाइपो है, स्पष्ट रूप से आप का मतलब था "बहुरूपता के साथ काम करना" उस कोड पर कॉपी / पेस्ट करने योग्य के बजाय: D
बेंजामिन Gruenbaum

@BenjaminGruenbaum निश्चित रूप से बहुरूपता की कुछ परिभाषा के लिए ;-)
Cort Ammon - Monica

@CortAmmon आप गलती से एक निजी विधि कैसे कहेंगे ? निश्चित रूप से तुम्हारा मतलब internal?
कोल जॉनसन

@ColeJohnson किसी भी तरह से। मैंने लिखा है कि एक विशिष्ट मामले के बारे में सोचकर, जहां मैं भाग रहा हूं, privateवह सार्थक है: कारखाने के तरीके जो कि क्लास का हिस्सा हैं, जो तात्कालिक हैं। मेरी स्थिति में, निजी मूल्यों तक पहुंच अपवाद नहीं होनी चाहिए। मैं कोड पर काम करता हूं जो मुझे लंबे समय तक आगे बढ़ाता है। यदि मैं इसे इस तरह से करता हूं, तो न केवल मैं स्वयं किसी भी निजी तरीके का उपयोग करने की संभावना नहीं रखता हूं, लेकिन जब अगले डेवलपर इसे कुछ दर्जन स्थानों पर कॉपी / पेस्ट करता है और उसके बाद डेवलपर उन्हें कॉपी करता है, तो यह उन बाधाओं को कम कर देता है जो किसी को एक अवसर दिखता है "सामान्य" व्यवहार के रूप में निजी तरीकों का उपयोग करें।
कॉर्ट अमोन -

21
  1. यह वाक्यविन्यास C ++ से बहुत अधिक विरासत है, जो कि, दोनों के पास है:

    Person Bob;

    तथा

    Person *bob = new Bob();

    पहला वर्तमान क्षेत्र के भीतर एक ऑब्जेक्ट बनाने के लिए, दूसरा डायनेमिक ऑब्जेक्ट के लिए पॉइंटर बनाने के लिए।

  2. आप निश्चित रूप से हो सकता है something_else Bob = new Person()

    IEnumerable<int> nums = new List<int>(){1,2,3,4}

    आप यहां दो अलग-अलग काम कर रहे हैं, स्थानीय चर के प्रकार को बताते हुए numsऔर आप कहते हैं कि आप 'सूची' के प्रकार की एक नई वस्तु बनाना चाहते हैं और इसे वहां रख सकते हैं।

  3. C # आपके साथ सहमत है, क्योंकि अधिकांश समय चर का प्रकार आपके द्वारा इसमें डाले गए समान है:

    var nums = new List<int>();
  4. कुछ भाषाओं में आप F # के रूप में चर के प्रकारों से बचने के लिए अपनी पूरी कोशिश करते हैं :

    let list123 = [ 1; 2; 3 ]

5
यह कहना शायद अधिक सटीक है कि आपका दूसरा उदाहरण एक नई बॉब ऑब्जेक्ट के लिए पॉइंटर बनाता है। जिस तरह से चीजों को संग्रहीत किया जाता है वह तकनीकी रूप से एक कार्यान्वयन विवरण है।
रॉबर्ट हार्वे

4
"स्टैक पर एक स्थानीय ऑब्जेक्ट बनाने के लिए पहला, दूसरा ढेर पर ऑब्जेक्ट बनाने के लिए।" अरे यार, यह गलत सूचना फिर नहीं।
लाइटनेस दौड़ मोनिका

@LightnessRacesinOrbit बेहतर है?
AK_

1
@AK_ जबकि "डायनेमिक" बहुत अधिक "हीप" (जब ढेर प्लेटफॉर्म द्वारा उपयोग किया जाने वाला मेमोरी मॉडल है) का अर्थ है, "स्वचालित" "स्टैक" से बहुत अलग है। यदि आप करते हैं new std::pair<int, char>(), तो सदस्यों firstऔर secondजोड़े की स्वचालित भंडारण अवधि होती है, लेकिन वे संभवतः ढेर पर आवंटित किए जाते हैं (जैसा कि डायनेमिक-स्टोरेज-अवधि pairऑब्जेक्ट के सदस्य )।
अंगे को अब एसओ पर गर्व नहीं है

1
@AK_: हाँ, उन नामों का ठीक वही अर्थ है जो उनका मतलब है, जबकि यह "स्टैक" बनाम "हीप" बकवास नहीं करता है । वह पूरा बिंदु है। कि आप उन्हें भ्रमित करते हुए पाते हैं कि हमें उन्हें पढ़ाने की आवश्यकता को पुष्ट करता है, ताकि आप गलत / गलत शब्दावली पर भरोसा नहीं कर रहे हैं क्योंकि यह परिचित है!
मोनिका

3

वहाँ के बीच एक बड़ा अंतर है int xऔर Person bob। एकint एक एक intहै intऔर यह हमेशा एक होना चाहिए intऔर एक के अलावा कुछ भी कभी नहीं हो सकता है int। यहां तक ​​कि intजब आप इसे घोषित करते हैं , तब भी आप इनिशियलाइज़ नहीं करते ( int x;), यह अभी भी intडिफ़ॉल्ट मान पर सेट है।

जब आप घोषणा करते हैं Person bob , हालांकि, लचीलेपन का एक बड़ा सौदा होता है, जैसा कि bobवास्तव में किसी भी समय नाम का उल्लेख हो सकता है। यह एक का उल्लेख कर सकते Personहैं, या यह कुछ अन्य वर्ग, जैसे की जानकारी दे सकती Programmer, से प्राप्त Person; यह भी हो सकता है null, कोई वस्तु का जिक्र नहीं है।

उदाहरण के लिए:

  Person bob   = null;
  Person carol = new Person();
  Person ted   = new Programmer();
  Person alice = personFactory.functionThatReturnsSomeKindOfPersonOrNull();

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


1

दोनों घोषणाएं अलग-अलग हो सकती हैं लेकिन अक्सर एक जैसी होती हैं। जावा में एक सामान्य, अनुशंसित पैटर्न इस प्रकार है:

List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

ये चर listऔर mapइंटरफेस का उपयोग करते हुए घोषित किए जाते हैं Listऔर Mapजबकि कोड विशिष्ट कार्यान्वयन को त्वरित करता है। इस तरह, बाकी कोड केवल इंटरफेस पर निर्भर करता है और एक अलग कार्यान्वयन कक्षाओं को तुरंत लेने के लिए आसान है, जैसे कि TreeMap, बाकी कोड किसी भी हिस्से पर निर्भर नहीं कर सकते हैंHashMap एपीआई के जो कि Mapइंटरफ़ेस के बाहर है।

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

प्रकार का अनुमान स्रोत कोड अतिरेक को ठीक कर सकता है। जैसे जावा में

List<String> listOne = Collections.emptyList();

प्रकार की सूची और घोषणा को धन्यवाद के सही प्रकार का निर्माण करेगा

static <T> List<T> emptyList(); 

कुछ भाषाओं में, प्रकार का अनुमान आगे जाता है, जैसे C ++ में

auto p = new Person();

BTW जावा लैंग्वेज लोअर केस आइडेंटिफायर नामों का उपयोग करने के लिए एक मजबूत कन्वेंशन सेट करती है, जैसे bob, नहीं Bob। यह बहुत सारी अस्पष्टता से बचता है उदाहरण के लिए package.Class बनाम Class.variable।
जैरी १०

... और इसीलिए आपके पास है clazz
बजे एक CVn

नहीं, clazzइसका उपयोग किया जाता है क्योंकि classयह एक कीवर्ड है इसलिए इसे पहचानकर्ता के रूप में उपयोग नहीं किया जा सकता है।
जेरी

... जो एक समस्या नहीं होगी अगर नामकरण सम्मेलनों के रूप में वे नहीं थे। Classपूरी तरह से मान्य पहचानकर्ता है।
cHao

... जैसे हैं cLaSs, cLASSऔर cLASs
el.pescado

1

आम आदमी के शब्दों में:

  • तात्कालिकता से अलग घोषणा करने से उन वस्तुओं का उपयोग करने में मदद मिलती है जो उन वस्तुओं का उपयोग करते हैं जो उन्हें बनाता है
  • जब आप ऐसा करते हैं, तब से बहुरूपता को सक्षम किया जाता है, जब तक कि तत्काल प्रकार घोषित प्रकार का एक उपप्रकार होता है, चर का उपयोग करने वाला सभी कोड काम करेगा
  • दृढ़ता से टाइप की गई भाषाओं में आपको अपने प्रकार को बताते हुए एक चर घोषित करना चाहिए, बस ऐसा करके var = new Process()आप पहले चर घोषित नहीं कर रहे हैं।

0

यह नियंत्रण के स्तर के बारे में भी है कि क्या हो रहा है। यदि किसी ऑब्जेक्ट / चर की घोषणा स्वचालित रूप से एक निर्माता को बुलाती है, उदाहरण के लिए, यदि

Person somePerson;

था स्वचालित रूप से के रूप में ही

Person somePerson = new Person(blah, blah..);

तब आप कभी भी (उदाहरण के लिए) डिफ़ॉल्ट फ़ैक्टर्स के बजाय ऑब्जेक्ट्स को इंस्टेंट करने के लिए स्थिर फ़ैक्टरी विधियों का उपयोग नहीं कर पाएंगे, यानी ऐसे समय होते हैं जब आप किसी नए ऑब्जेक्ट इंस्टेंस के लिए कंस्ट्रक्टर को कॉल नहीं करना चाहते हैं।

यह उदाहरण जोशुआ बलोच के प्रभावी जावा (आइटम 1 विडंबना पर्याप्त है!) में समझाया गया है।


पुस्तकों के बारे में, मेरी सी # पुस्तक और जावा पुस्तक दोनों जॉइस फैरेल की थीं। यह वही है जो पाठ्यक्रम निर्दिष्ट करता है। मैं भी C # और जावा पर विभिन्न यूट्यूब वीडियो के साथ पूरक है।
जेसन वोहल्गेमुथ

मैं आलोचना नहीं कर रहा था, सिर्फ यह
बताने के
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.