2009-12-18 21 views
71

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

def my_method(width, height, show_border) 
my_method(400, 50, false) 

आप इसे इस तरह से कर सकते हैं:

def my_method(options) 
my_method({"width" => 400, "height" => 50, "show_border" => false}) 

मैं इसके बारे में आपकी राय जानना चाहते हैं। क्या यह एक अच्छा या बुरा अभ्यास है, क्या हमें यह करना चाहिए या नहीं? इस अभ्यास का उपयोग करने वाली स्थिति में वैध है, और यह किस स्थिति में खतरनाक हो सकता है?

+2

+1, वास्तव में, एक अच्छा सवाल –

+10

एक छोटी सी टिप्पणी: '{चौड़ाई => 400, ऊंचाई => 50, show_border => झूठी}' मान्य नहीं माणिक वाक्य रचना है। मुझे लगता है कि आपका मतलब है {{चौड़ाई => 400,: ऊंचाई => 50,: show_border => false} 'या' {चौड़ाई: 400, ऊंचाई: 50, show_border: false} '(बाद वाला केवल रूबी 1.9 में मान्य है .1) – henrikhodne

उत्तर

24

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

मेरा सामान्य नियम यह है कि यदि आपके पास या तो विधि (3 या 4 से अधिक) या बहुत से वैकल्पिक तर्कों के लिए बहुत से तर्क हैं तो विकल्प हैश का उपयोग करें अन्यथा मानक तर्कों का उपयोग करें। हालांकि एक विकल्प हैश का उपयोग करते समय संभावित तर्कों का वर्णन करने वाली विधि परिभाषा के साथ हमेशा एक टिप्पणी शामिल करना महत्वपूर्ण है।

+1

अब, यदि मेरे पास विकल्प हैश है, तो क्या मैं अभी डाल सकता हूं पूरे हैश में, या क्या मुझे चाबियाँ => मान अलग-अलग पास करना है? – Pred

+1

यह सच है कि दोनों के पास फायदे और नुकसान हैं, हालांकि मैं सामान्य नियम से असहमत हूं। मेरा मानना ​​है कि विकल्प सामान्य बुरे अभ्यास में हैं और केवल तभी उपयोग किया जाना चाहिए जब समस्या हल करने का यही एकमात्र तरीका है। –

1

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

3

मुझे लगता है कि पैरामीटर पास करने की यह विधि बहुत स्पष्ट है जब कुछ पैरामीटर से अधिक हैं या जब कई वैकल्पिक पैरामीटर हैं। यह अनिवार्य रूप से विधि कॉल को स्पष्ट रूप से स्वयं-दस्तावेज बनाता है।

3

रूबी में औपचारिक मानकों के बजाय हैश का उपयोग करने के लिए यह सामान्य प्रथा नहीं है।

मुझे लगता है कि यह एक पैरामीटर के रूप में एक हैश पास करने का आम पैटर्न के साथ भ्रमित किया जा रहा है जब पैरामीटर जैसे मूल्यों के एक नंबर ले जा सकते हैं एक जीयूआई टूलकिट में एक विंडो की विशेषताएँ सेट करना।

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

भाषा सुविधा का दुरुपयोग न करें, इसका उपयोग कब करें और इसका उपयोग न करें।

+1

यदि आपको तर्कों की परिवर्तनीय संख्या की आवश्यकता है तो बस 'डीफ विधि (* तर्क)' का उपयोग करें, हैश उस विशेष समस्या को हल नहीं करते हैं – MBO

+1

संभावित भ्रम को इंगित करने के लिए धन्यवाद। मैं वास्तव में मूल पोस्टर के मामले के बारे में सोच रहा था जहां पैरामीटर का क्रम और संख्या परिवर्तनीय है। –

+1

उस बिंदु को जोड़ने के लिए, विरोधी पैटर्न को [जादू कंटेनर] के रूप में भी जाना जाता है (http://c2.com/cgi/wiki?MagicContainer) – jtzero

34

रूबी निहित हैश पैरामीटर है, तो आप भी

def my_method(options = {}) 

my_method(:width => 400, :height => 50, :show_border => false) 

और रूबी 1.9 और नए हैश वाक्य रचना के साथ लिख सकता है यह

my_method(width: 400, height: 50, show_border: false) 

हो सकता है एक समारोह से अधिक 3-4 पैरामीटर लेता है जब , यह देखना बहुत आसान है कि संबंधित पदों की गणना किए बिना, क्या है।

1

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

आप इस प्रश्न को बड़े मजबूत/कमजोर प्रकार की चर्चा के हिस्से के रूप में देख सकते हैं। यहां Steve yegge's ब्लॉग देखें। मैंने इस शैली का उपयोग सी और सी ++ में उन मामलों में किया है जहां मैं काफी लचीली बहस का समर्थन करना चाहता था। तर्कसंगत रूप से एक मानक HTTP GET, कुछ क्वेरी पैरामीटर के साथ बिल्कुल इस शैली है।

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

7

मैं कहना चाहता हूँ कि यदि आप या तो कर रहे हैं:

  1. अधिक से अधिक 6 विधि होने पैरामीटर
  2. विकल्पों कि कुछ आवश्यक है, कुछ वैकल्पिक और मूलभूत मूल्यों के साथ कुछ पासिंग

आप शायद एक हैश का उपयोग करना चाहते हैं। दस्तावेज में देखे बिना तर्कों का क्या अर्थ है यह देखना बहुत आसान है।

आप में से उन लोगों के लिए यह कहना मुश्किल है कि एक विधि क्या विकल्प लेती है, इसका मतलब यह है कि कोड खराब तरीके से दस्तावेज किया गया है। YARD के साथ, आप विकल्प निर्दिष्ट कर @option टैग का उपयोग कर सकते हैं:

## 
# Create a box. 
# 
# @param [Hash] options The options hash. 
# @option options [Numeric] :width The width of the box. 
# @option options [Numeric] :height The height of the box. 
# @option options [Boolean] :show_border (false) Whether to show a 
# border or not. 
def create_box(options={}) 
    options[:show_border] ||= false 
end 

लेकिन उस विशिष्ट उदाहरण में इस तरह के कुछ और सरल मानकों है, तो मुझे लगता है कि मैं इस के साथ जाना चाहते हैं:

## 
# Create a box. 
# 
# @param [Numeric] width The width of the box. 
# @param [Numeric] height The height of the box. 
# @param [Boolean] show_border Whether to show a border or not. 
def create_box(width, height, show_border=false) 
end 
1

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

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

लेकिन यदि उनमें से कोई भी सदस्य चर है तो हैश को हर बार पुनर्निर्मित किया जाना चाहिए।

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

फ़ंक्शन पैरामीटर बहुत बेहतर प्रदर्शन करते हैं।

2

एक Hash का उपयोग कर पैरामीटर के रूप में है कि आप संख्या और तर्क के आदेश पर निर्भरता को निकालना है के लाभ।

अभ्यास में इसका मतलब है कि बाद में क्लाइंट कोड के साथ संगतता को तोड़ने के बिना आपकी विधि को दोबारा बदलने/बदलने के लिए लचीलापन होगा (और लाइब्रेरी बनाने के दौरान यह बहुत अच्छा है क्योंकि आप वास्तव में क्लाइंट कोड नहीं बदल सकते हैं) ।

+0

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

+0

@ ड्रैगननिकोलिक मैं भी सैनी मेटज़ सामान के साथ बोर्ड पर हूं - मैनुअल पैरामीटर की एक सूची व्यवस्थित करने के लाभ बहुत बड़े हैं और – Mirv

+0

पुस्तक में स्वयं-दस्तावेज़ कोड के अन्य तरीके हैं, एक और चीज (मुझे शामिल !) अक्सर भूल जाते हैं कि पैरामीटर का क्रम भी एक निर्भरता है! इसका मतलब यह है कि केवल वैकल्पिक पैरा का उपयोग करने का अर्थ है कि आप किसी भी कारण से पैराम के क्रम को नहीं बदल सकते हैं (लेकिन आमतौर पर आप कई तर्क तर्कों को वैसे भी नहीं चाहते हैं!) –

0

सामान्य तौर पर हम हमेशा मानक तर्क का उपयोग करना चाहिए, जब तक यह संभव नहीं है (सैंडी मेट्स के "Practical Object-Oriented Design in Ruby" एक महान किताब अगर आप रूबी में सॉफ्टवेयर डिजाइन में रुचि रखते हैं है)। विकल्पों का उपयोग करते समय आपको उनका उपयोग करने की ज़रूरत नहीं है। मानक तर्क स्पष्ट और स्वयं-दस्तावेज (यदि सही ढंग से नामित हैं) हैं।

विकल्पों का उपयोग करने के लिए एक (और शायद एकमात्र) कारण यह है कि यदि फ़ंक्शन उन तर्कों को प्राप्त करता है जो प्रक्रिया नहीं करते हैं लेकिन बस किसी अन्य फ़ंक्शन पर जाते हैं।

यहाँ एक उदाहरण है, कि दिखाता है कि:

def myfactory(otype, *args) 
    if otype == "obj1" 
    myobj1(*args) 
    elsif otype == "obj2" 
    myobj2(*args) 
    else 
    puts("unknown object") 
    end 
end 

def myobj1(arg11) 
    puts("this is myobj1 #{arg11}") 
end 

def myobj2(arg21, arg22) 
    puts("this is myobj2 #{arg21} #{arg22}") 
end 

इस मामले 'myfactory' में भी 'myobj1' या 'myobj2' के लिए आवश्यक तर्क के बारे में पता नहीं है। 'मायफैक्ट्री' सिर्फ 'myobj1' और 'myobj2' के तर्कों को पास करता है और उनकी जांच और प्रक्रिया करने की उनकी ज़िम्मेदारी है।

0

हैश कई वैकल्पिक तर्कों को पारित करने के लिए विशेष रूप से उपयोगी हैं। मैं हैश का उपयोग करता हूं, उदाहरण के लिए एक वर्ग को प्रारंभ करने के लिए जिसका तर्क वैकल्पिक है।

उदाहरण

class Example 

def initialize(args = {}) 

    @code 

    code = args[:code] # No error but you have no control of the variable initialization. the default value is supplied by Hash 

    @code = args.fetch(:code) # returns IndexError exception if the argument wasn't passed. And the program stops 

    # Handling the execption 

    begin 

    @code = args.fetch(:code) 

    rescue 

@code = 0 

    end 

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