2009-06-08 19 views
7

मेरे पास एक वर्ग है जिसे आप किसी फ़ोल्डर में पास करते हैं और फिर यह निर्दिष्ट फ़ोल्डर के भीतर बहुत सारे डेटा को बंद करता है और प्रक्रिया करता है।सी # कन्स्ट्रक्टर डिजाइन

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

MyClass myClass = new MyClass(@"C:\temp"); 

अब यह क्या यह बंद हो जाता है और एक जोड़ी कहते हैं कि हजार फ़ाइलों को पढ़ता है और डेटा के साथ वर्ग भरता है। इस अपने सभी वर्ग करता है

MyClass myClass = new MyClass(); 
myClass.LoadFromDirectory(@"C:\temp"); 

उत्तर

22

हो सकता है कि आप उसे स्थिर विधि उस वस्तु का एक उदाहरण देता है के साथ इस तरह से कोशिश करनी चाहिए।

var myClass = MyClass.LoadFromDirectory(@"C:\temp"); 

यह आपके कन्स्ट्रक्टर के बाहर प्रारंभिक कोड रखेगा, साथ ही साथ आपको "एक पंक्ति" घोषणा जो आप ढूंढ रहे हैं।


पोस्टर से नीचे से टिप्पणी पर जा रहे हैं, राज्य एक कार्यान्वयन जोड़कर इसलिए की तरह हो सकता है:

public class MyClass 
{ 

#region Constructors 

    public MyClass(string directory) 
    { 
     this.Directory = directory; 
    } 

#endregion 

#region Properties 

    public MyClassState State {get;private set;} 

    private string _directory; 

    public string Directory 
    { 
     get { return _directory;} 
     private set 
     { 
      _directory = value; 
      if (string.IsNullOrEmpty(value)) 
       this.State = MyClassState.Unknown; 
      else 
       this.State = MyClassState.Initialized; 
     } 
    } 

#endregion 



    public void LoadFromDirectory() 
    { 
     if (this.State != MyClassState.Initialized || this.State != MyClassState.Loaded) 
      throw new InvalidStateException(); 

     // Do loading 

     this.State = MyClassState.Loaded; 
    } 

} 

public class InvalidStateException : Exception {} 


public enum MyClassState 
{ 
    Unknown, 
    Initialized, 
    Loaded 
} 
+0

अच्छा विचार, प्रारंभिकरण और कक्षा का उपयोग अक्सर काफी अलग होता है। यह अच्छी तरह से उन्हें अलग करता है। और भी अलगाव के लिए आप प्रारंभिक तर्क को कारखाने या निर्माता वर्ग में स्थानांतरित कर सकते हैं। – Mendelt

1

है:

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

कन्स्ट्रक्टर का उद्देश्य किसी वस्तु का निर्माण करना है। एक विधि का उद्देश्य एक कार्रवाई करना है। तो मेरा वोट इस फ़ॉर्म के लिए है:

MyClass myClass = new MyClass(); 
myClass.LoadFromDirectory(@"C:\temp"); 
+0

कक्षा में बहुत कुछ होगा और मैं इसे डिजाइन करने की प्रक्रिया में हूं। कक्षा के हिम्मत हालांकि यह आवश्यक है कि यह कक्षा में पारित डेटा के माध्यम से आबादी है। –

5

यह निर्भर करता है। आपको कक्षा के मूल उद्देश्य का मूल्यांकन करना चाहिए। यह क्या कार्य करता है?

जो मैं आमतौर पर पसंद करता हूं वह है कि क्लास कन्स्ट्रक्टर कक्षा के कामकाज के लिए आवश्यक प्रारंभिकरण करे। फिर मैं कक्षा पर विधियों को बुलाता हूं जो सुरक्षित रूप से मान सकते हैं कि आवश्यक प्रारंभिक कार्य किया गया है।

आम तौर पर, इनटाइलाइजेशन चरण बहुत गहन नहीं होना चाहिए। ऊपर ऐसा करने का एक वैकल्पिक तरीका हो सकता है:

// Instantiate the class and get ready to load data from files. 
MyClass myClass = new MyClass(@"C:\temp"); 

// Parse the file collection and load necessary data. 
myClass.PopulateData(); 
+0

यह वास्तव में एक सर्वोत्तम अभ्यास है और अधिकांश रिफैक्टरिंग टूल आपको अपने रचनाकारों से विधियों को कॉल नहीं करने के लिए कहेंगे जब तक कि वे प्रारंभिक विधियां नहीं हैं, जैसे नियंत्रण बनाना, या गुणों को सेट करना। –

+5

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

+0

@ जोन स्कीट, भयानक, सबसे अच्छी जगह नहीं है, लेकिन गहराई पुस्तक में आपके सी # ने मुझे बहुत मदद की है। धन्यवाद! - मेरी चिंता यह है कि इस वर्ग को डेटा को संसाधित करने में कई मिनट लग सकते हैं और दोहरी स्थिति होने से मैं बचने की उम्मीद कर रहा था। –

0

मुझे लगता है कि आप ऊपर ("पहले प्रारंभ दो दृष्टिकोणों के बीच तय करना चाहिए, तो "बनाम" खाली init निष्पादित करें, पैराम के साथ प्रदर्शन करें ") पर आधारित है कि क्या आप एक ही ऑब्जेक्ट को एक अलग इनपुट पर एक ही ऑपरेशन करने के लिए पुन: उपयोग करने की योजना बना रहे हैं।
यदि कक्षा केवल एक निश्चित पैरा पर कार्य चलाने के लिए उपयोग की जाती है, तो मैं इसे कन्स्ट्रक्टर (इसे पढ़ने के लिए भी) में शुरू करने के साथ जाऊंगा, और उसके बाद कार्य को एक अलग विधि पर करूँगा।
यदि आप अलग-अलग पैरा पर कार्य करना जारी रखना चाहते हैं, तो मैं इसे कार्य विधि में ही रखूंगा।

यदि सभी वर्ग यह कार्य करता है, तो मैं इसे सभी को स्थिर वर्ग/विधियों में बदलने पर भी विचार करता हूं - इसे अपनी आंतरिक स्थिति को रखने की आवश्यकता नहीं है।

वैसे भी, मैं कभी भी खुद को कन्स्ट्रक्टर में नहीं रखूंगा। जैसा कि सेरेब्रस ने कहा, प्रारंभिक होना चाहिए।

0

जब तक आपकी कक्षा का मुख्य उद्देश्य I/O निष्पादित नहीं करता है, तो संभवतः आपको कन्स्ट्रक्टर में I/O (संभावित रूप से IOException फेंकना) नहीं करना चाहिए। जबकि डेटा स्रोत फ़ाइल सामग्री से प्रारंभिक अवस्था बनाता

interface IMyDataSource 
{ 
    // ... 
} 

class FileDataSource: IMyDataSource 
{ 
    public FileDataSource(string path) 
    { 
     // ... 
    } 
} 

class MyClass 
{ 
    public MyClass(IMyDataSource source) 
    { 
     // ... 
    } 
} 

IMyDataSource myDS = new FileDataSource(@"C:\temp"); 
MyClass myClass = new MyClass(myDS); 

इस तरह मुख्य वर्ग का अपना राज्य के प्रबंधन पर ध्यान केंद्रित कर सकते हैं,:

दो में वर्ग विभाजन पर विचार करें।

+1

लेकिन अब FileDataSource में इसके कन्स्ट्रक्टर में अपवाद फेंकने की क्षमता है, इस प्रकार केवल त्रुटियों को एक अलग ऑब्जेक्ट में पास कर रहा है। –

+0

@ टॉम एंडरसन, यह विचार है। FileDataSource को I/O करने के लिए डिज़ाइन किया गया है ताकि कन्स्ट्रक्टर में I/O अपवादों की अपेक्षा की जा सके। MyClass I/O करने के लिए डिज़ाइन नहीं किया गया है, इसलिए कन्स्ट्रक्टर में I/O अपवादों से बचा जाता है। – finnw

0

यदि क्लास के साथ काम करने वाला एकमात्र संसाधन है, तो शायद यह कन्स्ट्रक्टर के मार्ग को पारित करने के लिए बेहतर होगा। अन्यथा, यह आपके वर्ग के सदस्यों के लिए एक पैरामीटर होगा।

0

मेरी व्यक्तिगत वरीयता सी # 3.0 प्रारंभकर्ताओं का उपयोग करना होगा।

class MyClass { 
    public string directory; 
    public void Load() { 
     // Load files from the current directory 
     } 
    } 

MyClass myClass = new MyClass{ directory = @"C:\temp" }; 
myClass.Load(); 

यह कुछ लाभ हैं:

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

हालांकि अभी भी एक बुरा दृष्टिकोण नहीं है, हालांकि यह एक राज्य, फ़ील्ड सेट या सेट नहीं है। –

0

मैं यहां "उन्हें विभाजित" लोगों को गूंजने जा रहा हूं। यदि यह मदद करता है, इस प्रयास करें:

  1. अपने आप से पूछें, "क्या करता है इस विधि/प्रॉपर्टी/क्षेत्र करते हैं?"
  2. इसे ऐसा करें; न आधिक न कम।

लागू करने कि यहाँ आप इस मिल:

  1. निर्माता वस्तु बनाने के लिए माना जाता है।
  2. आपकी विधि फाइल सिस्टम से अपना डेटा लोड करना चाहती है।

कि मुझे लगता है की तुलना में बहुत अधिक तार्किक होने के लिए "निर्माता वस्तु और फाइल सिस्टम से डेटा लोड बनाने के लिए माना जाता है।

+0

सहमत हुए। यदि आप ब्लॉक करना चाहते हैं और केवल तब वापस आना जब आपकी ऑब्जेक्ट वापस आबादी हो, तो एक स्थिर विधि वाले फैक्ट्री का उपयोग करें। – richardtallent

1

मैं एरी और अन्य लोगों से सहमत हूं - उन्हें विभाजित करें।

एक निर्माता को वास्तव में न्यूनतम मात्रा में काम करना चाहिए (बस उपयोग के लिए तैयार वस्तु को प्रारंभ करना और उस पर छोड़ देना)। काम करने के लिए एक अलग विधि का उपयोग करके:

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