2013-03-28 9 views
11

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

System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber()); 
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString()); 

यह भी कानून का उल्लंघन होगा:

public class Customer { 
    private String name; 
    private ContactInfo primaryAddress; 
    private ContactInfo workAddress; 
    private Interests hobbies; 
    //Etc... 

    public getPrimaryAddress() { return primaryAddress; } 
    public getWorkAddress() { return workAddress; } 
    public getHobbies() { return hobbies; } 
    //Etc... 
} 

private ContactInfo { 
    private String phoneNumber; 
    private String emailAddress; 
    //Etc... 

    public getPhoneNumber() { return phoneNumber; } 
    public getEmailAddress() { return emailAddress; } 
    //Etc... 
} 

private Interests { 
    private List listOfInterests; 
} 

निम्नलिखित दोनों Demeter के कानून का उल्लंघन होगा:

मान लीजिए कि आप इस तरह अन्य वस्तुओं से बना एक सुंदर मानक वस्तु, करते हैं डेमेटर, मुझे लगता है (स्पष्टीकरण?):

ContactInfo customerPrimaryAddress = customer.getPrimaryAddress(); 
System.out.println("Phone: " + customerPrimaryAddress.getPhoneNumber()); 

तो संभवतः, आप wou बस फोन

public getPrimaryPhoneNumber() { 
    return primaryAddress.getPhoneNumber(); 
} 

और फिर: ld फिर एक "getPrimaryPhoneNumber()" ग्राहक के लिए विधि जोड़ने println ("फोन:" + customer.getPrimaryPhoneNumber());

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

Customer.getSomeParticularAddress(addressType).getPhoneNumber(); 

यह लगता है जब आप कुछ एक मोबाइल फोन और एक लैंडलाइन फोन के लोगों के बारे में सोचने की तरह यह भी उन्मादपूर्ण प्राप्त कर सकते हैं, और फिर ContactInfo में फोन नंबरों का संग्रह होना चाहिए।

Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber(); 

जो मामले में, न केवल हम वस्तुओं के लिए वस्तुओं के भीतर वस्तुओं के भीतर बात कर रहे हैं, लेकिन हम भी पता है कि वैध addressType की और PHONETYPE के हैं। मैं निश्चित रूप से इसके साथ एक समस्या देख सकता हूं, लेकिन मुझे यकीन नहीं है कि इससे कैसे बचें। विशेष रूप से जब भी जो भी कक्षा इसे कॉल कर रही है, शायद यह जानती है कि वे ग्राहक के "प्राथमिक" पते के लिए "मोबाइल" फोन नंबर खींचना चाहते हैं।

इसे डेमेटर के कानून का अनुपालन करने के लिए कैसे प्रतिक्रिया दी जा सकती है और यह अच्छा क्यों होगा?

+7

मुझे लगता है कि आप भी इसे सचमुच ले जा रहे हैं, यह सिर्फ एक दिशानिर्देश के लिए संभव कोड बदबू आ रही है। आप क्या कर रहे हैं ठीक है। – Esailija

+2

Esailija के साथ सहमत, डेमेटर के कानून को वास्तव में गेटर्स पर आवेदन करने की आवश्यकता नहीं है, वे बहुत तुच्छ हैं। वास्तव में जो भी आप सुझाव देते हैं (ग्राहक .getPrimaryPhoneNumber()) ग्राहक को ContactInfo के आंतरिक पता करने के लिए नेतृत्व करेंगे। संरचना प्रकार ऑब्जेक्ट्स रखने का लाभ यह है कि आप सीमित करते हैं कि किसके लिए ContactInfo के बारे में जानना है, उदाहरण के लिए – Taylor

+0

ठीक है, मैं इस बिंदु को देखता हूं, लेकिन मेरे दिमाग में ContactInfo के अंदर सामान के लिए गैर-गेटर/सेटर परिदृश्य होने जा रहे हैं। मान लें कि आप ग्राहक को किसी लिंक या बटन से ईमेल करना चाहते हैं। आप इसे ग्राहक की तरह लिख सकते हैं .getSomeParticularContactInfo (addressType) .sendEmail() या customer.sendEmail() जो तब (ग्राहक के अंदर) कॉल प्राप्त करता है SomomeicicContactInfo ("प्राथमिक")। SendEmail()। या कुछ प्रबंधक वर्ग जैसे अन्य विकल्प हैं जो कार्रवाई को संभालते हैं। उदाहरण तब गेटर्स या सेटर्स के बारे में नहीं बनता है और मैं इस संदर्भ में डिज़ाइन निर्णय लेने के बारे में उलझन में हूं। –

उत्तर

2

मेरे अनुभव में, Customer उदाहरण दिखाया गया एक "मानक अन्य वस्तुओं से बना वस्तु," क्योंकि इस उदाहरण इनर क्लासों के रूप में अपनी रचना टुकड़े को लागू करने, और इसके अलावा उन इनर क्लासों निजी बनाने का जोड़ा कदम उठा लेता नहीं है। यह एक बुरी बात नहीं है।

आम तौर पर निजी एक्सेस संशोधक जानकारी छुपाता है, जो डेमेटर के कानून का आधार है। निजी वर्गों का खुलासा विरोधाभासी है। नेटबीन्स आईडीई में वास्तव में "सार्वजनिक एपीआई के माध्यम से गैर-सार्वजनिक प्रकार का निर्यात" के लिए एक डिफ़ॉल्ट कंपाइलर चेतावनी शामिल है।

मैं यह कहूंगा कि अपनी संलग्न कक्षा के बाहर एक निजी वर्ग का खुलासा करना हमेशा बुरा होता है: इससे सूचना छिपाने और डेमेटर के कानून का उल्लंघन होता है। तो के बाहर ContactInfo का उदाहरण लौटने के बारे में स्पष्टीकरण प्रश्न का उत्तर देने के लिए: हाँ, यह उल्लंघन है।

Customer करने के लिए एक getPrimaryPhoneNumber() विधि जोड़ने की प्रस्तावित समाधान एक मान्य विकल्प है। भ्रम यहां है: "ग्राहक ... अपने आंतरिक वर्गों के बारे में बहुत अधिक ज्ञान है।" यह संभव नहीं है; और यही कारण है कि यह महत्वपूर्ण है कि यह उदाहरण मानक संरचना उदाहरण नहीं है।

एक संलग्न कक्षा में किसी नेस्टेड कक्षाओं का 100% ज्ञान है। हमेशा। भले ही उन घोंसले वर्गों को संलग्न वर्ग (या कहीं और) में कैसे उपयोग किया जाता है। यही कारण है कि एक संलग्न वर्ग के पास निजी क्षेत्रों और इसके घोंसले वर्गों के तरीकों की सीधी पहुंच है: संलग्न वर्ग स्वाभाविक रूप से उनके बारे में सब कुछ जानता है, क्योंकि वे इसके अंदर लागू होते हैं।

कक्षा फू के पूर्वोत्तर उदाहरण को देखते हुए, जिसमें नेस्टेड क्लास बार है, जिसमें नेस्टेड क्लास बाज़ है, जिसमें नेस्टेड क्लास क्यूक्स है, यह कॉल बार के लिए फू (आंतरिक रूप से) के लिए डेमेटर का उल्लंघन नहीं होगा .baz.qux.method()। बार, बाज़ और क्यूक्स के बारे में जानने के लिए फू को पहले से ही सबकुछ पता है; क्योंकि उनका कोड फू के अंदर है, इसलिए लंबी विधि श्रृंखला के माध्यम से कोई अतिरिक्त ज्ञान नहीं पारित किया जा रहा है।

समाधान के बाद, डेमेटर के कानून के बाद समाधान Customer के लिए मध्यवर्ती वस्तुओं को वापस करने के लिए नहीं है, इसके आंतरिक कार्यान्वयन के बावजूद; यानी Customer कई नेस्टेड कक्षाओं या किसी भी का उपयोग करके लागू किया गया है, इसे केवल वही लौटाया जाना चाहिए जो इसके क्लाइंट क्लास को अंततः चाहिए।

उदाहरण के लिए पिछले कोड स्निपेट के रूप में पुनर्संशोधित हो सकता है, customer.getPhoneNumber(addressType, phoneType);

या अगर कोई Customer वर्ग के उपयोगकर्ताओं में विकल्पों में से केवल एक छोटी संख्या, customer.getPrimaryMobilePhoneNumber();

या तो दृष्टिकोण परिणाम हैं के बारे में पता किया जा रहा है इसका आंतरिक कार्यान्वयन, और यह सुनिश्चित करता है कि उन उपयोगकर्ताओं को उन वस्तुओं के माध्यम से कॉल न करें जिन्हें वे सीधे रुचि नहीं रखते हैं।

+0

संबंधित नहीं समझा गया: https: //javadevguy.wordpress।कॉम/2017/05/14/द-जीनियस-ऑफ-द-लॉ-ऑफ-डेमेटर/ – jaco0646

0

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

+0

यह एक अच्छा विकल्प है लेकिन परिणामस्वरूप कई प्रदाता वर्ग – swapyonubuntu

0

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

डेमेटर के कानून का उद्देश्य बाहरी वस्तुओं को किसी अन्य वस्तु के आंतरिक उपयोग तक पहुंचने में सक्षम होना है। आंतरिकों तक पहुंचने में दो समस्याएं हैं: 1) यह वस्तु की आंतरिक संरचना के बारे में बहुत अधिक जानकारी देता है, और 2) यह बाहरी वस्तुओं को कक्षा के आंतरिक भाग को संशोधित करने की अनुमति भी देता है।

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

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

(वास्तविकता में मैं आंतरिक वर्ग का नाम बदलने के हैं और ContactInfo के रूप में बाहरी एक छोड़ देते हैं, लेकिन यह है कि एक छोटी सी बात है)

तो यह Demeter के कानून के उद्देश्यों को प्राप्त है, लेकिन यह अभी भी लगता है कि हम तोड़ रहे हैं यह। जिस तरह से मैं इस बारे में सोचता हूं वह यह है कि getAddress विधि ContactInfo ऑब्जेक्ट को वापस नहीं कर रही है, लेकिन इसे तुरंत चालू कर रही है। इसका मतलब है कि डेमेटर नियमों के तहत हम ContactInfo के तरीकों तक पहुंच सकते हैं, और ऊपर लिखा गया कोड उल्लंघन नहीं है।

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

कुछ नोट्स। यह स्पष्ट है कि एक से अधिक सख्त Demeter के कानून के आवेदन उदाहरण के लिए मना, idiocies की ओर जाता है:

int nameLength = myObject.getName().length() 

एक तकनीकी उल्लंघन जो हम में से ज्यादातर हर दिन क्या करते जा रहा है। हर कोई भी करता है:

mylist.get(0).doSomething(); 

जो तकनीकी रूप से उल्लंघन है। लेकिन वास्तविकता यह है कि इनमें से कोई भी समस्या नहीं है जब तक कि हम वास्तव में बाहरी ऑब्जेक्ट (ग्राहक) के व्यवहार को प्रभावित करने वाले ऑब्जेक्ट्स के आधार पर बाहरी कोड को प्रभावित करने की अनुमति नहीं देते हैं।

सारांश

यहाँ अपने कोड की तरह दिखना चाहिए है:

public class Customer { 
    private class InternalContactInfo { 
     public ContactInfo createContactinfo() { 
      //creates a ContactInfo based on its own values... 
     } 
     //Etc.... 
    } 
    private String name; 
    private InternalContactInfo primaryAddress; 
    //Etc... 

    public Contactinfo getPrimaryAddress() { 
     // copies the info from InternalContactInfo to a new object 
     return primaryAddress.createContactInfo(); 
    } 
    //Etc... 
} 

public class ContactInfo { 
    // Not modifiable 
    private String phoneNumber; 
    private String emailAddress; 
    //Etc... 

    public getPhoneNumber() { return phoneNumber; } 
    public getEmailAddress() { return emailAddress; } 
    //Etc... 
} 

}

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