2017-02-13 12 views
8

मैं एक प्राथमिक निर्माता के साथ निम्न kotlin वर्ग, हैमाध्यमिक निर्माण वाक्य रचना kotlin

class Person(first: String, last: String, age: Int){ 

    init{ 
     println("Initializing") 
    } 

} 

मैं एक माध्यमिक निर्माता है कि एक first और last नाम में एक पूरा नाम पार्स करके प्राथमिक निर्माता कॉल जोड़ना चाहते हैं। हालांकि, मैं वाक्य रचना सही नहीं मिल सकता है ...

class Person(first: String, last: String, age: Int){ 

    // Secondary constructor 
    constructor(fullname: String, age: Int): 
     this("first", "last", age) 
     { 
      println("In secondary constructor") 
     } 

    init{ 
     println("Initializing") 
    } 
} 

यह ठीक काम करता है, क्योंकि मैं वास्तव में माध्यमिक निर्माता में fullname को पार्स कर रहा हूँ। जब मैं आगे बढ़ता हूं और पूर्ण नाम पार्स करने का प्रयास करता हूं,

constructor(fullname: String, age: Int): 
var first = fullname.split()[0]; 
... 
{ 
    println("In secondary constructor") 
} 

मुझे एक अनसुलझा संदर्भ मिलता है: पूर्ण नाम। यह दायरे में मौजूद नहीं है, लेकिन अगर मैं यह ब्रेसिज़ में डाल, तो मैं this के माध्यम से प्राथमिक निर्माता फोन नहीं कर सकते हैं,

constructor(fullname: String, age: Int): 
{ 
    var first = fullname 
    this(first, "foo", age) 
    println("In secondary constructor") 
} 

मैं एक लापता invoke समारोह से जुड़े कोई त्रुटि मिलती है।

कोटलिन दस्तावेज़ों पर इस मामले का एक अच्छा उदाहरण नहीं मिल रहा है, क्षमा करें।

+0

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

+0

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

+0

हां, आप इस तरह से माध्यमिक कन्स्ट्रक्टर का उपयोग नहीं कर सकते हैं। 'यह एक प्रतिनिधिमंडल है, यही कारण है कि आप इसे ब्रेसिज़ के भीतर उपयोग नहीं कर सकते हैं। आपको 'कन्स्ट्रक्टर (...) की रेखाओं के साथ कुछ करना होगा: यह (fullName.split ("") [0], fullName.split ("") [1])' जिसमें अनुक्रमण के लिए संभावित क्षमता है सीमाओं का –

उत्तर

2

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

class Person(first: String, last: String, age: Int) { 

    companion object { 
     fun fromFullNameAndAge(fullname: String, age: Int) : Person { 
      println("In secondary constructor") 
      var bits = fullname.split() 
      // Additional error checking can (and should) go in here. 
      return Person(bits[0],bits[1],age) 
     } 
    } 

    init{ 
     println("Initializing") 
    } 
} 

फिर आप इस

var p = Person.fromFullNameAndAge("John Doe", 27) 

कौन सा Person("John Doe", 27) के रूप में के रूप में साफ नहीं है, लेकिन IMO बहुत बुरा नहीं है की तरह उपयोग कर सकते हैं।

+0

ठीक है, धन्यवाद मिशेल। इस तरह की मुझे किसी कारण से पाइथन की याद दिलाती है। मुझे रचनाकार बनाने की याद आती है जिन्हें स्थैतिक तरीकों की तरह भी कहा जाता है। –

+0

अगली चीज़ जो आप जानते हैं, आपकी एपीआई स्थैतिक फैक्ट्री विधियों के साथ बाढ़ आ गई है जो कोने केस चेक करते हैं। क्या होगा यदि आप बाद में सोशल सिक्योरिटी नंबर जोड़ना चाहते थे, या शायद बदल सकते हैं कि नामों का विश्लेषण कैसे किया जाता है? कुछ सुंदर उपयोगी सिद्धांतों का उल्लंघन करने के लिए मजबूर होना होगा, जैसे कि ओपन/क्लोज़ –

+0

@ विन्सइम्घ अक्सर कन्स्ट्रक्टर/फ़ैक्टरी फ़ंक्शन _exactly_ वह जगह है जहां आप कोने केस चेक चाहते हैं, जो आपके कोड में एक दर्जन स्थानों में उन चेक को कूड़ेदान से कहीं बेहतर है। लेकिन, हमेशा के रूप में, यह संतुलन का मामला है। मैं हर मामले के लिए अंधाधुंध फैक्ट्री कार्यों के खिलाफ वकालत करता हूं - लेकिन यदि यह एक पैटर्न है जो कई बार फसलों का पालन करता है - तो इसके लिए निश्चित रूप से एक मामला बनाया जा सकता है। –

1

this के माध्यम से कन्स्ट्रक्टर कॉल पहली कॉल होना चाहिए। यही कारण है कि इसे एक सामान्य विधि के आमंत्रण के बजाय एक प्रतिनिधि के रूप में संभाला जाता है। इसका मतलब है कि कॉल को प्रतिनिधि से पहले आप चर घोषित नहीं कर सकते हैं।

आप बस को इनलाइन जो कुछ भी महत्व देता द्वारा इस का समाधान कर सकते हैं चर में संग्रहीत करने पर योजना बनाई:

constructor(fullName : String, age : int) : this(fullName.split(" ")[0], fullName.split(" ")[1]) 

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

डिजाइन विश्लेषण

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

इसके बजाय, आपको अपने प्राथमिक निर्माता का खुलासा करना चाहिए, उसके बाद Person का ग्राहक पहले और अंतिम नाम को अलग कर लेगा।

समाधान उदाहरण

कल्पना कीजिए कि हम एक फ़ाइल से नाम पढ़ रहे थे। फ़ाइल में प्रत्येक पंक्ति का पूरा नाम होता है। उन्हें बस एक नाम इनपुट, यह पार्स करने के बारे में चिंता किए बिना करने की अनुमति:

nameFile.forEachLine({ personList.add(Person(it)) }) 

यह लक्जरी आप अपने ग्राहकों को देने के लिए प्रयास कर रहे हैं है।

इससे समस्या सुरक्षा की कमी है: क्या होगा यदि लाइन में केवल पहला नाम है? क्या होगा अगर फ़ाइल ने पहले और अंतिम नाम को अलग करने के लिए व्हाइटस्पेस का उपयोग नहीं किया? अलग-अलग पहले/अंतिम नाम संयोजनों को संभालने के लिए आपको नए Person प्रकारों को परिभाषित करने के लिए मजबूर होना होगा।

इसके बजाय, पार्स वर्ग के बाहर होने चाहिए:

file.forEachLine({ 
    val firstName = ... 
    val secondName = ... 

    personList.add(Person(firstName, secondName)) 
}) 

अब जब कि जिम्मेदारी Person से बाहर ले जाया गया है, हम एक नई वस्तु को जिम्मेदारी दे सकते हैं, तो हम चाहते थे:

val parser = NameParser(" ") //specify delimiter 
file.forEachLine({ 
    val firstName = parser.extractFirstName(it) 
    val lastName = parser.extractLastName(it) 

    personList.add(Person(firsrName, lastName)) 
}) 
संबंधित मुद्दे