2008-10-29 14 views
35

विभिन्न विधियों के साथ डेटा के समान आकार को वापस करने वाली कई विधियों को परिभाषित करते समय बेहतर अभ्यास क्या है? स्पष्ट विधि नाम या अधिभारित तरीकों?विधि अधिभार। क्या आप इसका इस्तेमाल कर सकते हैं?

उदाहरण के लिए

। अगर मैं कुछ उत्पाद है और मैं किसी डेटाबेस से

स्पष्ट रास्ता खींच कर रहा हूँ:

public List<Product> GetProduct(int productId) { // return a List } 
public List<Product> GetProductByCategory(Category category) { // return a List } 
public List<Product> GetProductByName(string Name) { // return a List } 

अतिभारित रास्ता:

public List<Product> GetProducts() { // return a List of all products } 
public List<Product> GetProducts(Category category) { // return a List by Category } 
public List<Product> GetProducts(string searchString) { // return a List by search string } 

मैं तुम्हें समान हस्ताक्षर के साथ एक समस्या में पड़ सकता है एहसास , लेकिन यदि आप आधार प्रकारों (स्ट्रिंग, int, char, dateTime, आदि) के बजाय ऑब्जेक्ट पास कर रहे हैं तो यह एक समस्या से कम होगा। तो ... यह एक अच्छा विचार के लिए एक विधि तरीकों की संख्या के और स्पष्टता के लिए, याप्रत्येक विधि कि डेटा एक अलग तरह फिल्टर एक भिन्न तरीके से नाम होना चाहिए कम करने के लिए अधिभार है?

उत्तर

43

हां, अधिभार आसानी से अधिक उपयोग किया जा सकता है।

मुझे पता चला है कि एक ओवरलोड लोड किया गया है या नहीं, यह दर्शकों को विचार करना है - संकलक नहीं, लेकिन रखरखाव प्रोग्रामर जो सप्ताह/महीनों/वर्षों में साथ आ रहे हैं और समझना है कोड क्या हासिल करने की कोशिश कर रहा है।

GetProducts() जैसे एक साधारण विधि का नाम स्पष्ट और समझा जा सकता है, लेकिन यह बहुत असीमित छोड़ देता है।

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

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

समझाने के लिए, मैं खुशी से एक DeleteFile() विधि के लिए भार के उपयोग करेंगे:

public IList<Product> GetProductById(int productId) {...} 
public IList<Product> GetProductByCategory(Category category) {...} 
public IList<Product> GetProductByName(string Name) {...} 

पूर्ण होने:

void DeleteFile(string filePath); 
void DeleteFile(FileInfo file); 
void DeleteFile(DirectoryInfo directory, string fileName); 

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

// No collisions, even though both methods take int parameters 
public IList<Employee> GetEmployeesBySupervisor(int supervisorId); 
public IList<Employee> GetEmployeesByDepartment(int departmentId); 

वहाँ भी एक उद्देश्य के लिए अधिक भार पेश करने का अवसर है:

// Examples for GetEmployees 

public IList<Employee> GetEmployeesBySupervisor(int supervisorId); 
public IList<Employee> GetEmployeesBySupervisor(Supervisor supervisor); 
public IList<Employee> GetEmployeesBySupervisor(Person supervisor); 

public IList<Employee> GetEmployeesByDepartment(int departmentId); 
public IList<Employee> GetEmployeesByDepartment(Department department); 

// Examples for GetProduct 

public IList<Product> GetProductById(int productId) {...} 
public IList<Product> GetProductById(params int[] productId) {...} 

public IList<Product> GetProductByCategory(Category category) {...} 
public IList<Product> GetProductByCategory(IEnumerable<Category> category) {...} 
public IList<Product> GetProductByCategory(params Category[] category) {...} 

कोड एक बहुत अधिक की तुलना में यह लिखा है पढ़ने के लिए है - भले ही आप कभी नहीं आ स्रोत नियंत्रण में प्रारंभिक जांच के बाद कोड पर वापस, आप अभी भी कोड के उस पंक्ति को पढ़ने के लिए दो दर्जन बार पढ़ रहे हैं, जबकि आप निम्न कोड लिखते हैं।

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

+4

कई उदाहरणों के साथ बहुत अच्छी पोस्ट। धन्यवाद! – Armstrongest

+1

+1 हां, वास्तव में उपयोगी पोस्ट, चीयर्स! – andy

+2

+1 उत्कृष्ट सलाह, पूरी तरह से सहमत हैं। वास्तविक आवश्यकता के बिना विधि अधिभार बुरा है। मैं इसे जोड़ता हूं (जावा में कम से कम) यह सेटर्स – leonbloy

16

जहां तक ​​मैं कह सकता हूं, आपके पास कम तरीके नहीं होंगे, केवल कम नाम होंगे। मैं आम तौर पर नामकरण की ओवरलोडेड विधि प्रणाली पसंद करता हूं, लेकिन मुझे नहीं लगता कि जब तक आप टिप्पणी करते हैं और अपना कोड अच्छी तरह से दस्तावेज करते हैं (जिसे आपको किसी भी मामले में करना चाहिए) तब तक यह वास्तव में बहुत अंतर करता है।

1

एक और विकल्प "WHERE क्लॉज" बनाने के लिए क्वेरी ऑब्जेक्ट का उपयोग करना है। तो आपके पास इस तरह की एक विधि होगी:

public List<Product> GetProducts(Query query) 

क्वेरी ऑब्जेक्ट में ऑब्जेक्ट ओरिएंटेड तरीके से व्यक्त कंडिशन शामिल है। GetProducts क्वेरी ऑब्जेक्ट को "पार्सिंग" द्वारा क्वेरी प्राप्त करते हैं।

http://martinfowler.com/eaaCatalog/queryObject.html

+0

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

+0

यह एक क्लासिक एंटीपाटर है। – rmeador

+0

मुझे लगता है कि लिनक्यू जैसे ऑब्जेक्ट स्टोर के साथ कार्यान्वित करना मुश्किल होगा। लेकिन मैं उत्सुक हूँ। – Armstrongest

4

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

11

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

15

क्या आप इसका उपयोग कर सकते हैं? अच्छा, हाँ, यह सच है।

हालांकि, आपके द्वारा दिए गए उदाहरण विधि ओवरलोडिंग का उपयोग करने के सही उदाहरण हैं। वे सभी एक ही कार्य करते हैं, उन्हें अलग-अलग नाम क्यों देते हैं क्योंकि आप उन्हें विभिन्न प्रकार से गुजर रहे हैं।

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

1

हाँ आप इसे अति प्रयोग कर सकते हैं, फिर भी यहाँ एक और अवधारणा है जो मदद कर सकता है इसे नियंत्रण में रखने के उपयोग है ...

आप नेट का उपयोग कर रहे 3.5+ और एकाधिक फिल्टर आप शायद बेहतर हैं लागू करने के लिए की जरूरत है IQueryable और चेनिंग यानी उपयोग करने के लिए

GetQuery<Type>().ApplyCategoryFilter(category).ApplyProductNameFilter(productName); 

इस तरह आप फ़िल्टरिंग तर्क का पुन: उपयोग कर सकते हैं जिस पर आपको इसकी जरूरत है।

public static IQueryable<T> ApplyXYZFilter(this IQueryable<T> query, string filter) 
{ 
    return query.Where(XYZ => XYZ == filter); 
} 
+0

यह आकर्षक है। मेरे कार्यान्वयन में, मेरे पास लिंक डेटाकॉन्टेक्स्ट क्लास में आलेख, ArticleCategory, ArticleSubCategory आदि हैं। प्रत्येक विधि को वर्तमान में एक अलग संग्रहीत प्रक्रिया कहा जाता है। मुझे समझने के लिए वास्तव में IQueryable इंटरफ़ेस में खोदने की आवश्यकता है। – Armstrongest

+0

लिंक का स्थगित निष्पादन यह काम करता है कि यह कैसे काम करता है :) मुझे अपने सिर को IQueryable, जेनेरिक और एक्सटेंशन विधियों के आस-पास लाने में थोड़ी देर लग गई है, लेकिन मुझे कहना है कि मैं अब से कहीं अधिक प्रोग्रामिंग का आनंद लेता हूं। – JTew

1

जब आपने विधि के तर्कों में केवल सूक्ष्म मतभेद हैं तो मैंने अत्यधिक अधिभार देखा है। उदाहरण के लिए:

public List<Product> GetProduct(int productId) { // return a List } 
public List<Product> GetProduct(int productId, int ownerId) { // return a List } 
public List<Product> GetProduct(int productId, int vendorId, boolean printInvoice) { // return a List } 

मेरे छोटे उदाहरण में, यह जल्दी से स्पष्ट नहीं हो जाता है, तो दूसरा int तर्क मालिक या ग्राहक आईडी होना चाहिए।

+0

और यही कारण है कि आपको कोड में बहुत स्पष्ट टिप्पणियां (या जावाडोक, यदि यह जावा है, जो ऐसा प्रतीत होता है) डालना है ताकि अगला डेवलपर इसे समझ सके। – Elie

+0

यह सच है, और यह मैं क्या टालने की कोशिश कर रहा था। यही कारण है कि मुझे लगता है कि मुझे श्रेणी आईडी के बजाय ऑब्जेक्ट्स भेजने की आवश्यकता है ... – Armstrongest

+0

नहीं, बस बहुत सावधान रहें कि कोड और टिप्पणियां सहमत हैं ... और सुनिश्चित करें कि टिप्पणियां बहुत स्पष्ट हैं ... – Elie

5

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

विभिन्न विधि नामों के लिए एक और तर्क यह है कि वे इंटेलिजेंस का उपयोग करके अधिक आसानी से खोजे जा सकते हैं।

लेकिन किसी भी विकल्प के लिए पेशेवर और विपक्ष हैं - सभी डिज़ाइन व्यापार-बंद हैं।

4

अपने कोड का उपयोग कर किसी के सीखने की वक्र को कम करने के लिए ओवरलोडिंग का बिंदु ... और आपको नामकरण योजनाओं का उपयोग करने की अनुमति देने के लिए जो उपयोगकर्ता को यह बताता है कि विधि क्या करती है।

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

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

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

आप दो विधियों को ओवरलोड नहीं होना चाहिए अगर वे अलग अलग या असंबद्ध कार्य करते हैं ...

भ्रम की स्थिति के रूप में है कि मौजूद है जब आप

में के रूप में प्रकार द्वारा एक ही हस्ताक्षर के साथ दो तरीकों को ओवरलोड करना चाहते हैं कर सकते हैं
public List<Employee> GetEmployees(int supervisorId); 
public List<Employee> GetEmployees(int departmentId); // Not Allowed !! 

वैसे आप हस्ताक्षर भेद करने के लिए हमलावर कोर प्रकार के लिए रैपर के रूप में अलग प्रकार बना सकते हैं ..

public struct EmployeeId 
    { 
     private int empId; 
     public int EmployeeId { get { return empId; } set { empId = value; } } 
     public EmployeeId(int employeId) { empId = employeeId; } 
    } 

    public struct DepartmentId 
    { 
    // analogous content 
    } 

// Now it's fine, as the parameters are defined as distinct types... 
public List<Employee> GetEmployees(EmployeeId supervisorId); 
public List<Employee> GetEmployees(DepartmentId departmentId); 
+0

यह एक महान समाधान है! धन्यवाद! यहां कई अच्छी टिप्पणियां हैं। मैं एक से अधिक समाधान के रूप में एक से अधिक चुनना चाहता हूँ! यह निश्चित रूप से उनमें से एक है। – Armstrongest

+0

यह कुछ मामलों में हो सकता है, लेकिन यह जटिलता जोड़ता है। इसे अधिक उपयोग न करें। Structs में अपने सभी int आईडी लपेटना एक अच्छा समाधान नहीं है ... –

0

आप जितना चाहें ओवरलोडिंग का उपयोग कर सकते हैं। सर्वोत्तम प्रथाओं के दृष्टिकोण से भी, यह अनुशंसा की जाती है कि आप ओवरलोडिंग का उपयोग करें यदि आप डेटा पर "ऑपरेशन" (समग्र रूप से) करने की कोशिश कर रहे हैं। जैसे getProduct()

इसके अलावा, यदि आप जावा एपीआई देखते हैं, ओवरलोडिंग हर जगह है। आपको उससे बड़ा समर्थन नहीं मिलेगा।

1

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

  • डिफ़ॉल्ट कम भार के द्वारा प्रयोग किया जाता इंगित करने के लिए वर्णनात्मक पैरामीटर नाम का उपयोग करने के लिए क्या कोशिश।

  • AVOID ओवरलोड में मनमाने ढंग से भिन्न पैरामीटर नाम।

  • AVOID अधिभारित सदस्यों में पैरामीटर के क्रम में असंगत होने के कारण।

  • डीओ केवल सबसे लंबे अधिभार वर्चुअल (यदि विस्तारशीलता आवश्यक है) बनाते हैं। छोटे अधिभार को बस एक लंबे अधिभार के माध्यम से कॉल करना चाहिए।

  • नहीं उपयोग ref या out मापदंडों DO सदस्यों ओवरलोड।

  • डीओ वैकल्पिक तर्कों के लिए null को पारित करने की अनुमति दें।

  • डीओ डिफ़ॉल्ट तर्कों वाले सदस्यों को परिभाषित करने के बजाय सदस्य अधिभार का उपयोग करें।

0

ओवरलोडिंग वांछनीय बहुलक व्यवहार है। यह मानव प्रोग्रामर को विधि नाम याद रखने में मदद करता है। यदि प्रकार पैरामीटर के साथ स्पष्ट अनावश्यक है, तो यह खराब है। यदि प्रकार पैरामीटर यह नहीं बताता कि विधि क्या कर रही है, तो स्पष्ट समझने लगते हैं।

अपने उदाहरण में, getProductByName एकमात्र ऐसा मामला है जहां स्पष्ट हो सकता है, क्योंकि आप किसी अन्य स्ट्रिंग द्वारा उत्पाद प्राप्त करना चाहते हैं। यह समस्या आदिम प्रकार की अस्पष्टता के कारण हुई थी; getProduct (नाम n) कुछ मामलों में एक बेहतर अधिभार समाधान हो सकता है।

0

हाँ आप इसे अधिक उपयोग कर सकते हैं। आपके उदाहरण में ऐसा लगता है कि पहले और तीसरे शायद एक ही आइटम लौटाएंगे, जहां दूसरा कई वापस आएगा। यदि यह सही है, तो मैं पहले और तीसरे GetProduct और दूसरे GetProducts या GetProductList

यदि यह मामला नहीं है और सभी तीन कई लौटाते हैं (जैसे कि यदि आप इसे उत्पाद आईडी 5 पास करते हैं, तो यह किसी भी आइटम को वापस देता है 5 उत्पादक में, या स्ट्रिंग पैरामीटर के साथ किसी भी आइटम को उसके नाम पर देता है) तो मैं उन सभी तीन GetProducts या GetProductList को कॉल करता हूं और उन सभी को ओवरराइड करता हूं।

किसी भी घटना में, नाम को प्रतिबिंबित करना चाहिए कि फ़ंक्शन क्या करता है, इसलिए इसे उत्पाद की सूची लौटाते समय GetProduct (एकवचन) को कॉल करना अच्छा कार्य नाम नहीं बनाता है। IMNSHO

0

मैं "स्पष्ट" तरीके का कुल प्रशंसक हूं: प्रत्येक कार्य को एक अलग नाम दे रहा है। मैं भी, आदि कुछ कोड है जो अतीत में Add(...) कार्यों के बहुत सारे किया था, AddRecord(const Record&), AddCell(const Cell&) को,

पुनर्संशोधित किया है मैं इस, अनजाने डाले (C++, कम से कम) कुछ भ्रम और संकलक चेतावनी से बचने के लिए मदद करता है और यह स्पष्टता में सुधार करता है।

शायद कुछ मामलों में आपको अन्य रणनीति की आवश्यकता है। मुझे अभी तक कोई सामना नहीं हुआ है।

0

कैसे

public IList<Product> GetProducts() { /* Return all. */} 

public IList<Product> GetProductBy(int productId) {...} 
public IList<Product> GetProductBy(Category category) {...} 
public IList<Product> GetProductBy(string Name) {...} 

और इसी तरह के बारे में?

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