2008-10-01 5 views
6

मैंने अपना कोड व्यवस्थित किया है ताकि डेटा पदानुक्रमित रूप से व्यवस्थित हो। मैं अपने आप को इस तरह का कोड का उपयोग कर पेड़ पर रेंगने लगता है: अबक्या लंबी ऑब्जेक्ट इनोकेशन चेन के साथ स्वाभाविक रूप से गलत कुछ भी है?

File clientFolder = task.getActionPlan().getClientFile().getClient().getDocumentsFolder(); 

, के बाद से मैं काम वस्तु में गहरे उतर नहीं कर रहा हूँ, मैं अपने माता-पिता के लिए ऊपर ड्रिलिंग रहा हूँ, मुझे नहीं लगता कि मैं करना मैं encapsulation के मामले में कुछ खो रहा हूँ, लेकिन मेरे दिमाग के पीछे एक झंडा बंद हो रहा है मुझे बता रहा है कि इस तरह से करने के बारे में कुछ गंदा है।

विचार?

उत्तर

14

The Law of Demeter पर पढ़ें।

+1

हालांकि ध्यान दें कि इसे ओवरडोन किया जा सकता है। कॉलिंग a.getName()। बराबर ("blah") आवश्यक रूप से अपने परियोजना टारपीडो के लिए जा रहा नहीं है सिर्फ इसलिए कि आप एक पर एक compareNameTo() विधि नहीं लिखा है ... –

+0

यह सब के बारे में हो जाता है()। कॉलिंग प्राप्त करें()। बराबर() ठीक है क्योंकि केवल 1 मिलता है। प्राप्त करना()। प्राप्त करें()। बराबर() अलार्म घंटी ट्रिगर करने के लिए शुरू होना चाहिए। – Quibblesome

+0

लेकिन गरीब डेमेटर को कभी भी अंधेरे से लागू नहीं किया जाना चाहिए! हालांकि, प्राप्त होने पर सहमत हैं। –

0

दुनिया का सबसे बड़ा झंडा।

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

getClientFile() शून्य वापस आ सकता है और फिर getClient() विफल हो जाएगा और जब आप इसे पकड़ रहे हों, मान लें कि आप कोशिश कर रहे हैं तो आपको कोई संकेत नहीं मिलेगा कि कौन सा विफल रहा है।

+0

औसत प्राप्त अपवाद संदेशों को वापस करने वाले गेटर्स में एक नलपोइंटर अपवाद डालना बहुत मुश्किल है। –

+0

बेशक यह मानता है कि आप लेखक हैं और/या स्रोत हैं। यदि यह प्रोग्रामिंग अभ्यास का हिस्सा बन जाता है तो आप इस संभावना के बारे में सोचने का जोखिम नहीं चलाते हैं। – Bill

0

नल या अमान्य परिणाम प्राप्त करने की संभावना कितनी है? वह कोड कई कार्यों की सफल वापसी पर निर्भर है और शून्य सूचक अपवाद जैसी त्रुटियों को हल करना कठिन हो सकता है।

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

0

हां। यह सबसे अच्छा अभ्यास नहीं है। एक बात के लिए, अगर कोई बग है, तो इसे ढूंढना मुश्किल है। उदाहरण के लिए, आपका अपवाद हैंडलर एक स्टैक ट्रेस प्रदर्शित कर सकता है जो दिखाता है कि आपके पास लाइन 121 पर NullReferenceException है, लेकिन इनमें से कौन सी विधियां शून्य हो रही हैं? पता लगाने के लिए आपको कोड में खोदना होगा।

0

यह एक व्यक्तिपरक प्रश्न है लेकिन मुझे नहीं लगता कि इसके साथ कुछ भी गलत है। उदाहरण के लिए यदि श्रृंखला संपादक के पठनीय मैदान से परे फैली हुई है तो आपको कुछ स्थानीय लोगों को पेश करना चाहिए। उदाहरण के लिए, मेरे ब्राउज़र पर मैं अंतिम 3 कॉल नहीं देख सकता, इसलिए मुझे नहीं पता कि आप क्या कर रहे हैं :)।

0

वैसे यह निर्भर करता है। आपको उस तरह की वस्तु से नहीं पहुंचना चाहिए। यदि आप उन तरीकों के कार्यान्वयन को नियंत्रित करते हैं, तो मैं रिफैक्टरिंग की अनुशंसा करता हूं ताकि आपको ऐसा करने की आवश्यकता न हो।

अन्यथा, मैं जो कर रहा हूं उसे करने में कोई हानि नहीं दिखती है। यह निश्चित रूप से है की तुलना में बेहतर

ActionPlan AP = task.getActionPlan(); 
ClientFile CF = AP.getClientFile(); 
Client C = CF.getClient(); 
DocFolder DF = C.getDocumentsFolder(); 
4

ठीक है, हर अविवेक एक बिंदु जहां यह गलत हो सकता है कहते हैं।

विशेष रूप से, इस श्रृंखला में से कोई भी तरीका शून्य को वापस कर सकता है (सिद्धांत रूप में, आपके मामले में आपके पास ऐसी विधियां हो सकती हैं जो संभवतः ऐसा नहीं कर सकती हैं), और जब ऐसा होता है तो आपको पता चलेगा कि यह में से एक है उन विधियों, लेकिन नहीं जो एक है।

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

इसके अलावा मुझे इसके साथ कोई स्पष्ट समस्या नहीं दिखाई दे रही है।यदि आपके पास है, या कर सकता है, गारंटी देता है कि शून्य संदर्भ कोई समस्या नहीं होगी, तो वह वही करेगा जो आप चाहते हैं।

पठनीयता के बारे में क्या? यदि आप चर नाम जोड़ते हैं तो क्या यह स्पष्ट होगा? हमेशा एक कोड प्रोग्रामर द्वारा पढ़ा जाने का इरादा रखते हुए कोड लिखें, और केवल संयोग से संकलक द्वारा व्याख्या की जाए।

इस मामले में मुझे विधि कॉल की श्रृंखला को पढ़ना होगा और पता लगाना होगा ... ठीक है, यह एक दस्तावेज़ प्राप्त करता है, यह क्लाइंट का दस्तावेज़ है, क्लाइंट एक ... से आ रहा है ... ठीक है, और फ़ाइल एक कार्य योजना, आदि से है लांग चेन हो सकता है यह कम पठनीय से, कहते हैं कि बनाने के लिए, इस:

ActionPlan taskPlan = task.GetActionPlan(); 
ClientFile clientFileOfTaskPlan = taskPlan.GetClientFile(); 
Client clientOfTaskPlan = clientFileOfTaskPlan.GetClient(); 
File clientFolder = clientOfTaskPlan.getDocumentsFolder(); 

मैं इसे इस मामले पर व्यक्तिगत राय के लिए नीचे आता है लगता है।

+0

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

+0

डेमेटर के कानून द्वारा इतनी अच्छी तरह से कहा गया है कि टॉरबॉर्न द्वारा इंगित किया गया है, यह कोड गंभीर रूप से कई इंटरफेस के साथ मिलकर है, जो एक रखरखाव दुःस्वप्न में समाप्त हो जाएगा। – xtofl

+0

यह सही है, और मैं स्वीकार करूंगा कि मैंने उस विशेष कोण पर विचार नहीं किया है, मैंने पूरी तरह से उस हिस्से पर ध्यान केंद्रित किया है जिसे मैंने लिखा था। आप सही हैं, यह उन सभी निर्भरताओं के साथ एक रखरखाव दुःस्वप्न होगा। –

0

यह इतना बुरा नहीं है, लेकिन आपको 6 महीने में इसे पढ़ने में समस्याएं हो सकती हैं। या एक सहकर्मी को कोड को बनाए रखने/लिखने में समस्याएं हो सकती हैं, क्योंकि आपकी वस्तुओं की श्रृंखला काफी लंबी है।

और मैं आपको याद करता हूं कि आपको अपने कोड में चर प्रस्तुत करने की आवश्यकता नहीं है। इसलिए ऑब्जेक्ट्स को पता है कि उन्हें विधि से विधि तक कूदने की ज़रूरत है। (यहां सवाल उठता है यदि आपने थोड़ा अधिक नहीं किया है, लेकिन मैं कौन कहूं?)

मैं एक प्रकार की "सुविधा विधियों" पेश करता हूं। कल्पना कीजिए कि आप अपने "काम" में एक विधि मिला - इसके बाद आप निश्चित रूप से इस्तेमाल कर सकते हैं जैसे

task.getClientFromActionPlan(); 

वस्तु कुछ

task.getClientFromActionPlan().getDocumentsFolder(); 
बहुत अधिक पठनीय और मामले में आप इन "सुविधा तरीकों" सही करने (यानी के लिए

भारी इस्तेमाल ऑब्जेक्ट चेन), टाइप करने के लिए बहुत कम ;-)।

एडिथ कहता है: जब मैं उन्हें लिखता हूं तो इन सुविधा विधियों में अक्सर नलपोइंटर-जांच होती है। इस तरह आप नलपॉइंटर्स को अच्छे त्रुटि संदेशों के साथ भी फेंक सकते हैं (यानी "क्लाइंट को पुनर्प्राप्त करने का प्रयास करते समय एक्शनप्लान शून्य था")।

0

यह सवाल बहुत https://stackoverflow.com/questions/154864/function-chaining-how-many-is-too-many#155407

सामान्य में के करीब है, ऐसा लगता है लोगों का मानना ​​है कि वह भी लंबी श्रृंखला अच्छा नहीं कर रहे हैं और आप एक या दो से चिपके चाहिए सबसे ज्यादा जंजीर कॉल।

हालांकि मुझे लगता है कि पाइथन प्रशंसकों को बहुत मज़ा आता है। यह सिर्फ अफवाह हो सकती है ... :-)

2

सबसे पहले, इस तरह के कोड को ढेर करने से यह नलपोइंटर अपवादों का विश्लेषण करने और डीबगर में कदम उठाने के दौरान संदर्भों की जांच करने में परेशान हो सकता है।

इसके अलावा, मुझे लगता है कि यह सब नीचे उबलता है: क्या कॉलर को वह ज्ञान होना चाहिए?

शायद इसकी कार्यक्षमता को और अधिक सामान्य बनाया जा सकता है; फ़ाइल को इसके बजाय पैरामीटर के रूप में पारित किया जा सकता है। या, शायद एक्शनप्लान को यह भी प्रकट नहीं करना चाहिए कि इसका कार्यान्वयन क्लाइंटफ़ाइल पर आधारित है?

0

अपने अंतिम लक्ष्य के आधार पर आप भारी युग्मन से बचने और अंत में लागत से बचने के लिए शायद कम ज्ञान के प्रिंसिपल का उपयोग करना चाहते हैं। जैसे ही सिर इसे रखना पसंद करता है .. "केवल अपने दोस्तों से बात करें।"

1

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

0

चेनिंग का एक और महत्वपूर्ण उपज प्रदर्शन है।

ज्यादातर मामलों में यह एक बड़ा सौदा नहीं है, लेकिन विशेष रूप से एक लूप में आप संकेत को कम करके प्रदर्शन में उचित वृद्धि देख सकते हैं।

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

5

झंडा लाल है, और यह बोल्ड में दो बातें कहते हैं:

  • श्रृंखला का पालन करने के लिए यह आवश्यक है बुला कोड पूरे वृक्ष संरचना है, जो अच्छा कैप्सूलीकरण नहीं है पता करने के लिए के लिए, और
  • अगर पदानुक्रम कभी बदलता है आप कोड का एक बहुत कोष्ठक में

और एक बात को संपादित करना होगा:

  • एक संपत्ति का उपयोग करें, यानी task.getActionPlan() के बजाय task.ActionPlan

एक बेहतर समाधान हो सकता है - आप माता पिता के गुण ऊपर बच्चे स्तर पर पेड़ के सभी को बेनकाब करने की जरूरत है यह सोचते हैं - जाने के लिए बच्चों पर प्रत्यक्ष गुणों को आगे बढ़ाएं और लागू करें, यानी

File clientFolder = task.DocumentsFolder; 

यह कम से कम कॉलिंग कोड से वृक्ष संरचना को छुपाएगा। आंतरिक गुण की तरह लग रहे हो सकता है:

class Task { 
    public File DocumentsFolder { 
     get { return ActionPlan.DocumentsFolder; } 
    } 
    ... 
} 
class ActionPlan { 
    public File DocumentsFolder { 
     get { return ClientFile.DocumentsFolder: } 
    } 
    ... 
} 
class ClientFile { 
    public File DocumentsFolder { 
     get { return Client.DocumentsFolder; } 
    } 
    ... 
} 
class Client { 
    public File DocumentsFolder { 
     get { return ...; } //whatever it really is 
    } 
    ... 
} 

लेकिन भविष्य में वृक्ष संरचना में परिवर्तन आप केवल पेड़ में शामिल कक्षाओं में एक्सेसर काम करता है, और नहीं हर जगह है जहाँ आप श्रृंखला को बुलाया बदलना होगा अगर ।

[प्लस यह जाल करने के लिए आसान हो सकता है और संपत्ति काम करता है, जो ऊपर के उदाहरण से निकाल दिया गया में ठीक से nulls रिपोर्ट करेंगे]

1

कैसे समय पर। मैं इस ब्लॉग के बारे में आज रात अपने ब्लॉग पर एक पोस्ट लिखने जा रहा हूं, Message Chains, इसके विपरीत, Middle Man बनाम।

किसी भी तरह, एक गहन सवाल यह है कि आपके पास डोमेन ऑब्जेक्ट होने पर "प्राप्त" विधियां क्यों हैं। यदि आप समस्या के रूप में बारीकी से पालन करते हैं, तो आप या तो यह पता लगाएंगे कि कुछ पाने के लिए कोई कार्य बताने के लिए यह समझ में नहीं आता है, या जो भी आप कर रहे हैं वह वास्तव में एक गैर-व्यावसायिक तर्क चिंता है जैसे यूआई डिस्प्ले की तैयारी, दृढ़ता, वस्तु पुनर्निर्माण, आदि

बाद के मामले में, तब तक "प्राप्त करें" विधियां ठीक हैं जब तक वे used by authorized classes हैं।आप नीति को कैसे लागू करते हैं प्लेटफॉर्म-और प्रक्रिया-निर्भर है।

तो ऐसे मामले में जहां "प्राप्त करें" विधियों को ठीक समझा जाता है, आपको अभी भी समस्या का सामना करना पड़ता है। और दुर्भाग्यवश, मुझे लगता है कि यह उस वर्ग पर निर्भर करता है जो श्रृंखला को नेविगेट कर रहा है। यदि उस वर्ग के लिए यह संरचना के लिए उपयुक्त है (कहें, एक कारखाना), तो इसे होने दें। अन्यथा, आपको Hide Delegate पर आज़माएं।

संपादित करें: click here for my post

3

Getters and setters are evil। आम तौर पर, इसके साथ कुछ करने के लिए ऑब्जेक्ट प्राप्त करने से बचें। इसके बजाय कार्य को स्वयं ही प्रतिनिधि दें।

Object a = b.getA(); 
doSomething(a); 

के बजाय

b.doSomething(); 

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

+0

पिछले वर्ष के भीतर, मैं इस दर्शन में परिवर्तित हो गया हूं। आप सही हैं कि आप उन्हें पूरी तरह से नहीं बचा सकते हैं। कुंजी या तो उन तरीकों तक पहुंच प्रतिबंधित करने के लिए प्रक्रिया या प्लेटफ़ॉर्म विधियों का उपयोग करना है, जिन्हें केवल उन वस्तुओं के लिए उपयोग करना है जिन्हें बिल्कुल उपयोग करना है। – moffdub

0

मैं भी डेमेटर के कानून को इंगित करता हूं।

और जोड़ने Tell, Don't Ask

1

बारे में एक लेख आप वास्तविक कभी उन कार्यों को स्वतंत्र रूप से में से हर एक का उपयोग करने जा रहे हैं? क्यों न केवल कार्य को GetDocumentsFolder() विधि है जो आपके लिए उन सभी विधियों को कॉल करने के सभी गंदे काम करता है? फिर आप उन जगहों पर अपने कोड को क्रूट किए बिना शून्य-जांच सबकुछ के सभी गंदे काम कर सकते हैं जहां इसे क्रूर होने की आवश्यकता नहीं है।

+0

यदि आप छुपा प्रतिनिधियों के साथ बहुत दूर जाते हैं, तो आप मध्य पुरुषों के अलावा कुछ भी नहीं खत्म करते हैं। – moffdub

0

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

अंग पर बाहर जाना, क्या ये सभी वर्ग एक ही चीज़ के लिए विशेष नाम हैं? यानी वे पदानुक्रमित हैं, लेकिन प्रत्येक स्तर में कुछ अतिरिक्त गुण हो सकते हैं?

तो, एक अलग कोण से, मैं एक enum और एक इंटरफ़ेस को सरल बनाने जा रहा हूं, जहां बच्चे कक्षाएं अनुरोध की गई चीज़ नहीं हैं तो श्रृंखला वर्ग का प्रतिनिधि बनती है। तर्क के लिए, मैं उन्हें फ़ोल्डर्स कह रहा हूं।

enum FolderType { ActionPlan, ClientFile, Client, etc } 

interface IFolder 
{ 
    IFolder FindTypeViaParent(FolderType folderType) 
} 

और प्रत्येक वर्ग कि IFolder लागू करता है शायद सिर्फ

IFolder FindTypeViaParent(FolderType folderType) 
{ 
    if(myFolderType == folderType) 
     return this; 

    if(parent == null) 
     return null; 

    IFolder parentIFolder = (IFolder)parent; 
    return parentIFolder.FindTypeViaParent(folderType) 
} 

एक बदलाव IFolder इंटरफेस बनाने के लिए है करता है:

interface IFolder 
{ 
    FolderType FolderType { get; } 
    IFolder Parent { get; } 
} 

यह आपको ट्रेवर्सल कोड बाह्यरूप की अनुमति देता है। हालांकि यह कक्षाओं से दूर नियंत्रण लेता है (शायद उनके पास एकाधिक माता-पिता हैं) और कार्यान्वयन का खुलासा करता है। अच्छा और बुरा।

[ramblings]

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

फिर फिर, पदानुक्रम वास्तव में वस्तु पहचान का एक हिस्सा है? यदि ऐसा नहीं है, तो शायद आप पदानुक्रम को एन-आरी पेड़ के रूप में बाहरी कर सकते हैं।

एक साइड-नोट के रूप में, आप कुल मिलाकर डीडीडी (डोमेन संचालित डिजाइन) अवधारणा पर विचार करना चाहेंगे और यह निर्धारित कर सकते हैं कि प्रमुख खिलाड़ी कौन हैं। परम मालिक वस्तु क्या है जो जिम्मेदार है? जैसे एक कार के पहिये एक डिजाइन में जो एक कार मॉडल करता है, पहियों भी वस्तुएं हैं, लेकिन वे कार के स्वामित्व में हैं।

शायद यह आपके लिए काम करता है, शायद यह नहीं करता है। जैसे मैंने कहा, यह अंधेरे में सिर्फ एक शॉट है।

+0

आपकी तर्क ध्वनि है, सिवाय इसके कि विभिन्न वर्गों के साथ पदानुक्रम विभिन्न वर्गों से बना है। हालांकि अंधेरे में अच्छा शॉट। –

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