2014-09-10 3 views
5

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

  • पठनीयता
  • प्रदर्शन
  • डिबगिंग में आसानी
  • OO सिद्धांतों (कम युग्मन और उच्च सामंजस्य)

स्पष्ट रूप का उपयोग करते हुए सक्रिय समर्थन

person.try(:pet).try(:name).try(:upcase) 

से कोशिश विधि एक बचाव का प्रयोग नहीं के बराबर

person.pet.name.upcase rescue nil 

एक & & ऑपरेटर श्रृंखला

person && person.pet && person.pet.name && person.pet.name.upcase 

बंदर वस्तु वर्ग पैच का उपयोग करना, मूल सार

के लिए https://gist.github.com/thegrubbsian/3499234 देखना
class Object 

     def try_all(*methods) 
     values = [self] 
     methods.each do |method| 
      value = values.last.try(method) 
      return nil if value.nil? 
      values << value 
     end 
     values.last 
     end 

    end 

person.try_all(:pet, :name, :upcase) 

सुरक्षित कोड नहीं के बराबर नहीं है, बजाय डेटा को मान्य इससे पहले कि आप कोड फोन

#not a good implementation by any means  
def person_has_pet_with_name? person 
    begin 
    return true if !person.pet.name.nil? 
    rescue 
    return false 
    end 
end 

person.pet.name.upcase if person_has_pet_with_name?(person) 
+0

क्या मेरा उत्तर आपको किसी भी तरह से मदद करता है? –

+0

अगर उत्तर आपके प्रश्न का उत्तर दिया गया है तो कृपया प्रश्न को हल करें। –

उत्तर

4

सामान्य रूप में बंदर पैचिंग के बारे में मेरे व्यक्तिगत राय यह मत करो जब तक कि वहाँ कोई दूसरा रास्ता नहीं है (और यहां तक अगर मैं वास्तव में बंदर पैच करना चाहता हूं तो मुझे दो बार लगता है)।
रेल के अलावा पहले से ही वस्तुओं को फूला हुआ है। इसलिए मैं कस्टम ब्लोएटिंग ऑब्जेक्ट्स को और भी सुझाव नहीं दूंगा।
क्यों क्लासिक डैलिगेटर दृष्टिकोण से Demeter के कानून तोड़ने से परहेज नहीं:

class Person 
    attr_accessor :pet 
    delegate :name_upcased, to: :pet, 
    prefix: true, allow_nil: true 
end 

class Pet 
    attr_accessor :name 
    def name_upcased 
    @name.upcase if @name 
    end 
end 

@person.try :pet_name_upcased 

तुम भी Do not break the law of Demeter! और Module#delegate पर Demeter के कानून के बारे में पढ़ सकते हैं।
कम से कम मैं Object#try तक नहीं टिकूंगा जब तक कि एक साधारण स्थिति हल हो जाती है, क्योंकि 'कोशिश' के स्रोत को देखते हुए यह स्थिति की तुलना में अधिक महंगा होता है।

0

मैं लंबे समय से कॉल जंजीरों से बचने के रूप में वे चाहते हैं Law of Demeter का स्पष्ट उल्लंघन कर रहे हैं:

person.try(:pet).try(:name).try(:upcase) 

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

class Person 
    def upcased_pet_name 
    pet.try(:upcased_name) 
    end 
end 

class Pet 
    def upcased_name 
    name.try(:upcase) 
    end 
end 

# Simple method call. nil checks are handled elsewhere 
person.try(:upcased_pet_name) 

अपने परीक्षण में, यह अब person ठूंठ एक बहुत आसान है, और अपने कोड एक बहुत पढ़ने के लिए आसान है।

+0

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

+0

'अगर' दृष्टिकोण आपने भी बहुत अच्छी तरह से काम किया है, आंशिक रूप से क्योंकि यह सादे रूबी में भी काम करता है। यह मेरे कोड के लिए एक अच्छा refactoring हो सकता है। – fivedigit

0

डेमेटर के कानून के साथ समस्या यह है कि आपकी कक्षाएं एक-दूसरे के बारे में बहुत अधिक जानती हैं, जिससे उन्हें अधिक कसकर जोड़ दिया जाता है, जिससे बदले में उन्हें अधिक गड़बड़ और परीक्षण करना कठिन होता है।

मेरे अनुभव में, डेमेटर के कानून का सबसे लगातार उल्लंघन विचारों में है।चूंकि आप नाम को पूंजीकृत करने की कोशिश कर रहे हैं, इसलिए मुझे लगता है कि यह मामला यहां है। Soooo ....

क्या आप एक दृश्य सहायक का उपयोग कर सकते हैं?

def upcased_name(entity_with_name) 
    if entity_with_name != nil 
     entity_with_name.name.try(:upcase) 
    end 
end 

फिर अपने ध्यान में रखते हुए, तो आप सिर्फ फोन

<% upcased_name(person.pet) %> 

आप viewhelper को अलग-इंजेक्शन लगाने के द्वारा upcased_pet_name परीक्षण कर सकते हैं: क्षमा करें, रेल में बहुत अच्छा नहीं है, इसलिए इस pseudocodish है।

अब

:

  • आपका दृश्य जानता है केवल वह है upcased_name नामक एक viewhelper के लिए एक 'व्यक्ति', और उपयोग करने के लिए उपयोग किया है।
  • आपका Person मॉडल केवल जानता है कि इसमें Pet विधि है।
  • आपका व्यूअर केवल यह जानता है कि यह एक नाम विधि, या nil के साथ एक इकाई प्राप्त कर सकता है।

बूम! आपकी कक्षाएं केवल अपने दोस्तों के बारे में जानती हैं, और उनके दोस्तों के दोस्तों के बारे में कुछ भी नहीं।

+0

आपके कोड में कुछ समस्याएं शामिल हैं। सबसे पहले मैं इसे एक सहायक में नहीं डालूंगा, क्योंकि यह केवल एक चिंता चिंता नहीं है। फिर <% = upcased_name (person.pet)%><% upcased_name (person.pet)%> के बजाय> और यदि व्यक्ति शून्य है तो क्या होगा? फिर entity_with_name.name.try (: अपकेस) अगर entity_with_name.nil? कठोरता के बजाय अगर entity_with_name! = शून्य और कम से कम प्रतिनिधिदाता दृष्टिकोण कोशिश करने की तुलना में चिकनी काम करता है, जो अधिक महंगा है और परीक्षण और त्रुटि अभिव्यक्ति को अधिक संदर्भित करता है। –

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