2009-06-25 13 views
17

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

कहें कि आपको किसी निश्चित प्रकार की फ़ाइल को संसाधित करने के लिए मूल "फ़ाइल रीडर/फ़ाइल लेखक" शैली वर्ग लिखने की आवश्यकता है। आइए फ़ाइल को YadaKungFoo फ़ाइल पर कॉल करें। YadaKungFoo फ़ाइलों की सामग्री अनिवार्य रूप से आईएनआई फ़ाइलों के समान है, लेकिन सूक्ष्म मतभेदों के साथ।

वर्गों और मूल्यों के होते हैं:

[Sections] 
Kung,Foo 
Panda, Kongo 

[AnotherSection] 
Yada,Yada,Yada 
Subtle,Difference,Here,Yes 

[Dependencies] 
PreProcess,SomeStuffToPreDo 
PreProcess,MoreStuff 
PostProcess,AfterEight 
PostProcess,TheEndIsNear 
PostProcess,TheEnd 

ठीक है, तो यह 3 बुनियादी वर्गों उपज कर सकते हैं: एक toString() ओवरराइड करने के लिए साथ

public class YadaKungFooFile 
public class YadaKungFooFileSection 
public class YadaKungFooFileSectionValue 

दो उत्तरार्द्ध वर्ग हैं अनिवार्य रूप से केवल डाटा संरचनाओं कुछ जेनेरिक सूचियों का उपयोग करके संग्रहीत मूल्यों की एक स्ट्रिंग सूची थूकें। यह YadaKungFooFile कार्यक्षमता कार्यक्षमता को लागू करने के लिए पर्याप्त है।

तो समय के साथ YadaYadaFile बढ़ने लगती है। एक्सएमएल इत्यादि सहित विभिन्न प्रारूपों में सहेजने के लिए कई ओवरलोड, और फ़ाइल 800 लाइनों या उससे भी आगे बढ़ने लगती है। अब वास्तविक प्रश्न: हम YadaKungFoo फ़ाइल की सामग्री को सत्यापित करने के लिए एक सुविधा जोड़ना चाहते हैं। पहली बात जो दिमाग में आती है वह स्पष्ट रूप से जोड़ना है:

var yada = new YadaKungFooFile("C:\Path"); 
var res = yada .Validate() 

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

var yada = new YadaKungFooFile("C:\Path"); 
var validator = new YadaKungFooFileValidator(yada); 
var result = validator.Validate(); 

अब इस नमूने जाहिर बहुत सरल, तुच्छ और तुच्छ है। शायद ऊपर दो तरीकों में से या तो बहुत ज्यादा फर्क नहीं है, लेकिन क्या मुझे पसंद नहीं है यह है:

  1. YadaKungFooFileValidator वर्ग और YadaKungFooFile वर्ग बहुत दृढ़ता से इस डिजाइन से मिलकर हो रहे हैं । ऐसा लगता है कि एक वर्ग में बदलाव आया है, दूसरे में बदलावों की संभावना है।
  2. मुझे पता है कि "वैलिडेटर", "कंट्रोलर", "प्रबंधक" आदि जैसे वाक्यांश ... एक वर्ग को इंगित करते हैं जो अन्य वस्तुओं की स्थिति से संबंधित है, जो इसके "अपने व्यवसाय" के विपरीत है, और इसलिए अलगाव का उल्लंघन करता है चिंता सिद्धांतों और संदेश भेजने का।

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

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

उत्तर

15

बॉब मार्टिन वर्ग डिजाइन, पर लेख की एक श्रृंखला है जो वह ठोस सिद्धांतों के रूप में को संदर्भित करता है लिखा है:

http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

सिद्धांत होते हैं:

  1. एकल जिम्मेदारी सिद्धांत: एक कक्षा में एक होना चाहिए, और केवल एक, बदलने का कारण होना चाहिए।
  2. ओपन-क्लोज़ड सिद्धांत: आपको इसे संशोधित किए बिना कक्षा व्यवहार का विस्तार करने में सक्षम होना चाहिए।
  3. लिस्कोव प्रतिस्थापन सिद्धांत: व्युत्पन्न कक्षाएं उनके मूल वर्गों के लिए प्रतिस्थापन योग्य होनी चाहिए।
  4. इंटरफेस पृथक्करण सिद्धांत: अच्छी तरह से दाग वाले इंटरफेस बनाएं जो क्लाइंट विशिष्ट हैं।
  5. निर्भरता उलटा सिद्धांत: विवेकानुसार नहीं, अवशेषों पर निर्भर करता है।

तो उन के प्रकाश में, के बयानों में से कुछ को देखो:

तो समय के साथ बढ़ रहा है YadaYadaFile शुरू होता है। कई भार के एक्सएमएल आदि सहित विभिन्न प्रारूपों में बचाने के लिए, और फ़ाइल 800 लाइनों की दिशा में आगे बढ़ाने शुरू होता है या तो

यह एक पहले बिग रेड फ्लैग है: 1) एक वर्ग/कुंजी को बनाए रखने: YadaYadaFile दो जिम्मेदारियों के साथ बाहर शुरू होता है/मूल्य डेटा संरचना, और 2) एक आईएनआई जैसी फ़ाइल को पढ़ने और लिखने के बारे में जानना। तो पहली समस्या है। अधिक फ़ाइल प्रारूपों को जोड़ना समस्या को जोड़ता है: YadaYadaFile तब बदलता है जब 1) डेटा संरचना में परिवर्तन होता है, या 2) फ़ाइल प्रारूप में परिवर्तन होता है, या 3) एक नया फ़ाइल प्रारूप जोड़ा जाता है।

इसी प्रकार, उन सभी तीन जिम्मेदारियों के लिए एक वैधकर्ता होने के कारण उस एकल वर्ग पर बहुत ज़िम्मेदारी है।

एक बड़ी कक्षा एक "कोड गंध" है: यह अपने आप में बुरा नहीं है, लेकिन यह अक्सर ऐसा कुछ होता है जो वास्तव में बुरा होता है - इस मामले में, एक वर्ग जो बहुत सी चीजों की कोशिश करता है।

2

मैं इस

YadaKungFooFileValidator वर्ग और YadaKungFooFile वर्ग बहुत दृढ़ता से इस डिजाइन से मिलकर होने लगते हैं को संबोधित करेंगे। यह एक वर्ग में एक बदलाव लगता है, संभवतः दूसरे में परिवर्तन ट्रिगर करेगा।

हां, तो इसके प्रकाश में, यह समझें कि इसे जितना संभव हो सके निर्बाध बनाना है। सबसे अच्छे मामले में, YadaKungFooFile क्लास को इस तरह से डिज़ाइन करें कि सत्यापनकर्ता इसे स्वयं ही उठा सकता है।

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

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

तो पर और आगे ...

14

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

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

+4

"मुझे नहीं लगता कि कक्षा का आकार चिंता का विषय है।" सिद्धांत में मैं सहमत होने का लुत्फ उठा रहा हूं। प्रैक्टिस में, मैंने कभी भी 2000 से अधिक लाइनों वाली कक्षा नहीं देखी है जिसे मुझे पसंद आया। – PeterAllenWebb

+1

@ पीटर एलेन वेब ... मैं सहमत हूं, लेकिन एलओसी की संख्या निर्णायक कारक नहीं होनी चाहिए, बल्कि कक्षा के अर्थशास्त्र को यह तय करने में मदद करनी चाहिए कि क्या कक्षा एक चीज़ या एक से अधिक चीज़ों से संबंधित है। हकीकत में ज्यादातर वर्ग छोटे होने जा रहे हैं। –

+1

@ विंसेन्ट रामधनी एलओएल गंध का वास्तव में अच्छा संकेतक है, मेरा सामान्य नियम यह है कि यदि एक विधि में 100 से अधिक एलओसी हैं तो यह सुनिश्चित नहीं है कि सिद्ध मासूम और कक्षाओं के लिए 500 एलओसी –

0

इस मामले में चीजों को संभालने का मेरा व्यक्तिगत तरीका एक वर्ग YadaKungFooFile होगा जो YadaKungFooFileSections की एक सूची से बना होगा, जो YadaKungFooFileValues ​​की एक सूची होगी।

वैधकर्ता के मामले में, आप प्रत्येक वर्ग को नीचे के वर्ग की वैध विधि कॉल करेंगे, पदानुक्रम में निम्नतम श्रेणी सत्यापन विधि के वास्तविक मांस को लागू करेगी।

0

यदि सत्यापन पूरी फ़ाइल पर निर्भर नहीं है बल्कि इसके बजाय केवल अलग-अलग अनुभाग मानों पर काम करता है, तो आप अनुभाग मूल्यों पर चल रहे वैधकर्ताओं का एक सेट निर्दिष्ट करके YadaKungFooFile क्लास के सत्यापन को विघटित कर सकते हैं।

यदि सत्यापन पूरी फ़ाइल पर निर्भर करता है तो सत्यापन स्वाभाविक रूप से फ़ाइल वर्ग के साथ मिलकर होता है और आपको इसे एक वर्ग में डालने पर विचार करना चाहिए।

0

कक्षा का आकार विधि के आकार के रूप में कोई समस्या नहीं है। कक्षाएं संगठन का साधन हैं और आपके कोड को व्यवस्थित करने के अच्छे और बुरे तरीके हैं, लेकिन यह सीधे कक्षा के आकार से बंधे नहीं है।

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

मुझे लगता है कि विधि आकार निर्धारित करने का सबसे अच्छा तरीका यूनिट परीक्षणों के लेखन के माध्यम से है। यदि आप पर्याप्त कोड कवरेज के साथ यूनिट परीक्षण लिख रहे हैं तो यह तब स्पष्ट हो जाता है जब कोई विधि बहुत बड़ी हो।

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

4

YadaKungFooFile को डिस्क से खुद को पढ़ने के बारे में नहीं पता होना चाहिए। इसे केवल अपने बच्चों को प्रकट करने, अपने बच्चों को प्रकट करने आदि के बारे में पता होना चाहिए।

IYadaKungFooReader इंटरफ़ेस होना चाहिए कि YadaKungFooFile अपनी लोड विधि में ले जाएगा जो इसे स्वयं लोड करने के लिए उपयोग करेगा डिस्क से इसके अलावा कई कार्यान्वयन जैसे AbstractKungFooReader, PlainTextYadaKungFooReader, XMLYadaKungFooWriter जो जानते हैं कि कैसे पढ़ना और संबंधित प्रारूपों को पढ़ना है।

लेखन के लिए वही।

अंत में, YadaKungFooValidatingReader होना चाहिए जो IYadaKungFooReader रीडर ले जाएगा, इसे पढ़ने के लिए इनपुट को पढ़ने और मान्य करने के लिए इसका उपयोग करें। फिर आप मान्य पाठक को YadaKungFooFile पर पास कर देंगे। जब भी आप इसे डिस्क से पढ़ते हैं तो इसे सत्यापित करना चाहते हैं।

वैकल्पिक रूप से, आप निष्क्रिय कक्षा के बजाय पाठक को सक्रिय बना सकते हैं। फिर, इसे YadaKungFooFile में पास करने के बजाय, आप इसे एक कारखाने के रूप में उपयोग करेंगे जो बाद में सामान्य पहुंच विधियों का उपयोग करके आपका YadaKungFooFile बना देगा। इस मामले में आपके पाठक को YadaKungFooFile इंटरफ़ेस को भी कार्यान्वित करना चाहिए ताकि आप सामान्य पाठक -> पाठक को सत्यापित कर सकें -> YadaKungFooFile। समझ में आता है?

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