2016-11-30 7 views
8

मैं एक साधारण प्रोग्राम तैयार करने के तरीके से असहज हूं। FileParser ऑब्जेक्ट है जिसमें OnFileOpened, OnLineParsed, और OnFileClosed ईवेंट हैं, और कई ऑब्जेक्ट्स जो फ़ाइल की सामग्री के आधार पर छोटी फ़ाइलों को बनाते हैं जो FileParser पार्स हैं।ऑडिओमैटिक सी # ऑब्जेक्ट के लिए केवल इंटरैक्टिंग के बावजूद घटनाओं पर पंजीकृत होने के बावजूद

FileParser देख रहे ऑब्जेक्ट्स उनके कन्स्ट्रक्टर में FileParser ईवेंट के साथ अपने तरीकों को पंजीकृत करते हैं।

ParsedFileFrobber(FileParser fileParser) 
{ 
    fileParser.OnFileOpen += this.OpenNewFrobFile; 
    fileParser.OnLineParsed += this.WriteFrobbedLine; 
    fileParser.OnFileClose += this.CloseFrobFile; 
} 

उसके बाद, ParsedFileFrobber बस आगे स्पष्ट सहभागिता के बिना चीजों के साथ पर हो जाता है।

जो चीज मुझे परेशान करती है वह यह है कि मुख्य कार्यक्रम केवल ParsedFileFrobber असाइन करता है और मूल रूप से कन्स्ट्रक्टर के वापसी मूल्य का उपयोग नहीं करता है।

var fileParser = new FileParser(myFilename); 
var parsedFileFrobber = new ParsedFileFrobber(fileParser); 
// No further mentions of parsedFileFrobber. 

यह काम करता है, लेकिन रीशेर्पर इस बारे में शिकायत करता है, जो कम से कम मुझे सोचने के लिए रोक देता है। असल में, मुझे कन्स्ट्रक्टर के नतीजे के लिए एक वैरिएबल असाइन करने की भी आवश्यकता नहीं है, क्योंकि जीसी इवेंट हैंडलर संदर्भों की योग्यता से ParsedFileFrobber जीवित रखेगी, लेकिन एक नंगे new मेरे लिए बहुत गलत लग रहा है। (यह अभी भी संकलित और सही ढंग से चलता है।)

var fileParser = new FileParser(myFilename); 
new ParsedFileFrobber(fileParser); 

क्या यह कोई समस्या है? क्या यह एक विरोधी पैटर्न या कोड गंध है? क्या सी # में ऐसा करने का एक बेवकूफ तरीका है?

धन्यवाद!

स्पष्टीकरण मददगार टिप्पणियाँ करने के लिए धन्यवाद:

1) क्यों रिश्ते को उलटने के नहीं? कोडी ग्रे

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

2) कन्स्ट्रक्टर को स्थिर विधि में क्यों नहीं ले जाएं (और कन्स्ट्रक्टर को निजी बनाएं)? हंस पासेंट

मैं देख सकता हूं कि कक्षा के निजी आंतरिक कार्यों में संभावित रूप से अनजान उपयोग को दूर करने के लिए यह कैसे अच्छी तरह से तैयार है, जो अच्छी सलाह है। हालांकि, यह अभी भी नंगे new या कन्स्ट्रक्टर के रिटर्न वैल्यू का एकमात्र निर्दिष्ट संदर्भ होगा। खैर, अगर यह एक बड़ी समस्या नहीं है, तो बदसूरत कोड को छिपाने के लिए यह समझ में आता है। (संदर्भ के लिए, मैं Dispose विधि घटनाओं से सदस्यता समाप्ति के साथ ParsedFileFrobber एक IDisposable बनाने के लिए किया था, तो यह frobbing को समाप्त कर दिया जा सकता है।)

आप सभी टिप्पणीकर्ताओं को धन्यवाद!

+2

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

+2

इस बारे में बहुत परेशान नहीं है, बस एक अच्छा अनुस्मारक है कि यह तब तक हमेशा के लिए फिसलने जा रहा है जब तक कि फ़ाइलपार्स ऑब्जेक्ट जीवित रहता है। आप ParseFileFrobber को एक स्थिर विधि जोड़कर इसे "प्राकृतिक" बना सकते हैं। इसे नाम दें, एर्म, फ्रोब() या निरीक्षण करें()। कन्स्ट्रक्टर निजी बनाओ। –

+0

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

उत्तर

0

अंत में मैं कुछ हंस पासेंट की सिफारिश की गई थी: एक स्थिर विधि के आंतरिक कार्यों में नंगे नए को दूर करना।

1

Mediator pattern का उपयोग करने का एक संभावित समाधान हो सकता है, जो एक नई कक्षा पेश करता है जो आपके FileParser और ParsedFile* कक्षाओं के बीच बातचीत को नियंत्रित करता है:। इस तरह आपकी कक्षाएं बहुत कम हो जाती हैं, आपके FileParser को ParsedFileFrobber और इसके विपरीत के बारे में जानने की आवश्यकता नहीं है। मध्यस्थ वर्ग वस्तुओं के जीवनकाल का भी ख्याल रख सकता है।

public interface IParsedFile 
{ 
    void OnOpen(); 
    void OnLineParsed(string line); 
    void OnClosed(); 
} 

public class FileParseManager 
{ 
    private readonly FileParser _fileParser; 
    private readonly List<IParsedFile> _parsedFiles; 

    public FileParseManager(FileParser fileParser, List<IParsedFile> parsedFiles) 
    { 
     _fileParser = fileParser; 
     _parsedFiles = parsedFiles; 
    } 

    public void Parse(string fileName) 
    { 
     _fileParser.OpenFile(string fileName); 
     foreach (var parsedFile in _parsedFiles) 
     { 
      parsedFile.OnOpen(); 
     } 

     while ((string line = _fileParser.GetNextLine()) != null) 
     { 
      foreach (var parsedFile in _parsedFiles) 
      { 
       parsedFile.OnLineParsed(line); 
      } 
     } 

     _fileParser.CloseFile(); 
     foreach (var parsedFile in _parsedFiles) 
     { 
      parsedFile.OnClosed(); 
     } 
    } 
} 

एक अन्य विकल्प निर्माता-उपभोक्त पैटर्न का उपयोग करने के लिए हो सकता है। ऐसा कुछ प्रदान किया जाता है उदा। .NET फ्रेमवर्क में टीपीएल (टास्क समांतर लाइब्रेरी) द्वारा। Dataflow section और वहां दिए गए उदाहरण देखें।

+0

मैं संदर्भों की सराहना करता हूं, लेकिन ऐसा लगता है कि घटना-हैंडलर प्रणाली के प्रभाव को स्पष्ट रूप से बिना किसी स्पष्ट लाभ के पुन: उत्पन्न करना प्रतीत होता है, खासकर जब ग्रोबबर के लिए ऑनऑपेन() उदाहरण के लिए जरूरी नहीं है, जबकि यहां यह होगा लागू किया जाना चाहिए (नो-ऑप के रूप में)। –

संबंधित मुद्दे