एक बेहतर अभ्यास कौन सा है - सहायक विधियाँ उदाहरण के लिए या स्थिर?


48

यह सवाल व्यक्तिपरक है लेकिन मैं बस उत्सुक था कि अधिकांश प्रोग्रामर इस पर कैसे पहुंचें। नीचे का नमूना छद्म-सी # में है, लेकिन यह जावा, सी ++ और अन्य ओओपी भाषाओं पर भी लागू होना चाहिए।

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

class Foo
{
  Bar _bar;

  public void DoSomethingWithBar()
  {
    // Method Call #1.
    DoSomethingWithBarImpl();

    // Method Call #2.
    DoSomethingWithBarImpl(_bar);
  }

  private void DoSomethingWithBarImpl()
  {
    _bar.DoSomething();
  }

  private static void DoSomethingWithBarImpl(Bar bar)
  {
    bar.DoSomething();
  }
}

ऐसा करने का मेरा कारण यह है कि यह स्पष्ट है (मेरी आँखों में कम से कम) कि सहायक विधि का अन्य वस्तुओं पर एक संभावित दुष्प्रभाव है - यहां तक ​​कि इसके कार्यान्वयन को पढ़ने के बिना भी। मुझे लगता है कि मैं जल्दी से इस पद्धति का उपयोग कर सकता हूं और इस तरह चीजों को डिबग करने में मेरी मदद कर सकता हूं।

आप अपने कोड में क्या करना पसंद करते हैं और ऐसा करने के आपके कारण क्या हैं?


3
मैं C ++ को इस प्रश्न से हटा दूंगा: C ++ में, जाहिर है, आप इसे एक नि: शुल्क विधि बना देंगे, क्योंकि इसका कोई मतलब नहीं है कि यह मनमाने ढंग से किसी वस्तु में टकरा जाए: यह ADL को निष्क्रिय कर देता है।
मैथ्यू एम।

1
@ मैथ्यूएमएम .: नि: शुल्क विधि या नहीं, इससे कोई फर्क नहीं पड़ता। मेरे प्रश्न का आशय यह पूछना था कि क्या सहायक विधियों को उदाहरण के रूप में घोषित करने में कोई लाभ हैं। तो C ++ में चुनाव उदाहरण विधि बनाम मुक्त विधि / फ़ंक्शन हो सकता है। आपको ADL के बारे में एक अच्छी बात मिल गई है। तो क्या आप कह रहे हैं कि आप मुफ्त तरीकों का उपयोग करना पसंद करेंगे? धन्यवाद!
इलियन

2
सी ++ के लिए, मुफ्त तरीकों की सिफारिश की जाती है। वे इनकैप्सुलेशन को बढ़ाते हैं (अप्रत्यक्ष रूप से, केवल सार्वजनिक इंटरफ़ेस तक पहुंचने में सक्षम होने के नाते) और अभी भी एडीएल (विशेषकर टेम्प्लेट) के कारण अच्छा खेलते हैं। हालाँकि, मुझे नहीं पता कि यह जावा / सी # पर लागू होता है, सी ++ जावा / सी # से बहुत भिन्न होता है, इसलिए मुझे अलग-अलग जवाब देने की उम्मीद है (और इस तरह मुझे नहीं लगता कि एक साथ 3 भाषाओं के लिए पूछने का मतलब है)।
Matthieu M.

डुप्लिकेट: stackoverflow.com/questions/3604137/… :)
nawfal

1
किसी को भी उत्तेजित करने की कोशिश किए बिना, मैंने स्थैतिक तरीकों का उपयोग नहीं करने का एक अच्छा कारण कभी नहीं सुना है। मैं उनका उपयोग करता हूं जहां भी मैं कर सकता हूं, क्योंकि वे यह स्पष्ट करते हैं कि विधि क्या करती है।
श्रीधर सरनोबत

जवाबों:


23

यह वास्तव में निर्भर करता है। यदि आपके मददगार जिन मूल्यों पर काम करते हैं, वे आदिम हैं, तो स्थैतिक विधियाँ एक अच्छा विकल्प हैं, जैसा कि Péter ने बताया है।

वे जटिल हैं, तो ठोस लागू होता है, और अधिक विशेष एस , मैं और डी

उदाहरण:

class CookieJar {
      function takeCookies(count:Int):Array<Cookie> { ... }
      function countCookies():Int { ... }
      function ressuplyCookies(cookies:Array<Cookie>
      ... // lot of stuff we don't care about now
}

class CookieFan {
      function getHunger():Float;
      function eatCookies(cookies:Array<Cookie>):Smile { ... }
}

class OurHouse {
      var jake:CookieFan;
      var jane:CookieFan;
      var cookies:CookieJar;
      function makeEveryBodyAsHappyAsPossible():Void {
           //perform a lot of operations on jake, jane and the cookies
      }
      public function cookieTime():Void {
           makeEveryBodyAsHappyAsPossible();
      }
}

यह आपकी समस्या के बारे में होगा। आप एक स्थिर विधि बना सकते हैं makeEveryBodyAsHappyAsPossible, जो आवश्यक मापदंडों में ले जाएगा। एक अन्य विकल्प है:

interface CookieDistributor {
    function distributeCookies(to:Array<CookieFan>):Array<Smile>;
}
class HappynessMaximizingDistributor implements CookieDistributor {
    var jar:CookieJar;
    function distributeCookies(to:Array<CookieFan>):Array<Smile> {
         //put the logic of makeEveryBodyAsHappyAsPossible here
    }
}
//and make a change here
class OurHouse {
      var jake:CookieFan;
      var jane:CookieFan;
      var cookies:CookieDistributor;

      public function cookieTime():Void {
           cookies.distributeCookies([jake, jane]);
      }
}

अब OurHouseकुकी वितरण नियमों की पेचीदगियों के बारे में जानने की जरूरत नहीं है। यह केवल अब एक वस्तु होनी चाहिए, जो एक नियम को लागू करती है। कार्यान्वयन एक वस्तु में दूर हो गया है, जो नियम को लागू करने के लिए एकमात्र जिम्मेदारी है। इस वस्तु का अलगाव में परीक्षण किया जा सकता है। OurHouseका मात्र उपयोग करके परीक्षण किया जा सकता है CookieDistributor। और आप आसानी से कुकी वितरण नियमों को बदलने का निर्णय ले सकते हैं।

हालाँकि, ध्यान रखें कि आप इसे ज़्यादा न करें। उदाहरण के लिए 30 कक्षाओं की एक जटिल प्रणाली के कार्यान्वयन के रूप में कार्य करता है CookieDistributor, जहां प्रत्येक वर्ग केवल एक छोटे से काम को पूरा करता है, वास्तव में कोई मतलब नहीं है। एसआरपी की मेरी व्याख्या यह है कि यह केवल यह निर्धारित नहीं करता है कि प्रत्येक वर्ग के पास केवल एक जिम्मेदारी हो सकती है, बल्कि यह भी है कि एक एकल वर्ग द्वारा एक ही जिम्मेदारी निभाई जानी चाहिए।

प्राइमिटिव्स या ऑब्जेक्ट्स के मामले में आप प्रिमिटिव्स की तरह उपयोग करते हैं (उदाहरण के लिए स्पेस, मैट्रीज या कुछ और में पॉइंट्स का प्रतिनिधित्व करने वाले ऑब्जेक्ट्स), स्टैटिक हेल्पर क्लासेस बहुत मायने रखती हैं। यदि आपके पास विकल्प है, और यह वास्तव में समझ में आता है, तो आप वास्तव में डेटा का प्रतिनिधित्व करने वाले वर्ग के लिए एक विधि जोड़ने पर विचार कर सकते हैं, जैसे कि यह Pointएक addविधि के लिए समझदार है । फिर से, इसे ज़्यादा मत करो।

तो आपकी समस्या के आधार पर, इसके बारे में जाने के विभिन्न तरीके हैं।


18

उपयोगिता वर्गों के तरीकों की घोषणा करना एक अच्छी तरह से ज्ञात मुहावरा है static, इसलिए ऐसी कक्षाओं को कभी भी तत्काल शुरू करने की आवश्यकता नहीं है। इस मुहावरे के बाद आपके कोड को समझना आसान हो जाता है, जो एक अच्छी बात है।

हालांकि इस दृष्टिकोण के लिए एक गंभीर सीमा है: ऐसे तरीकों / वर्गों को आसानी से मजाक नहीं किया जा सकता है (हालांकि AFAIK कम से कम C # के लिए मॉकिंग फ्रेमवर्क हैं जो यह भी प्राप्त कर सकते हैं, लेकिन वे आम नहीं हैं और कम से कम उनमें से कुछ हैं व्यावसायिक)। इसलिए यदि किसी सहायक विधि में कोई बाह्य निर्भरता (जैसे DB) है जो इसे बनाती है - इस प्रकार इसके कॉलर - यूनिट टेस्ट के लिए कठिन है, तो इसे गैर-स्थिर घोषित करना बेहतर है । यह निर्भरता इंजेक्शन की अनुमति देता है, इस प्रकार विधि के कॉलर्स को इकाई परीक्षण के लिए आसान बनाता है।

अपडेट करें

स्पष्टता: उपयोगिता वर्गों के बारे में उपरोक्त वार्ता, जिसमें केवल निम्न स्तर की सहायक विधियाँ हैं और (आमतौर पर) कोई स्थिति नहीं है। स्टेटफुल नॉन-यूटिलिटी क्लासेस के अंदर हेल्पर तरीके एक अलग मुद्दा है; ओपी की गलत व्याख्या के लिए माफी।

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


क्या आप सिर्फ स्थैतिक सहायक विधि पर निर्भरता को पारित नहीं कर सकते हैं?
इलियान

1
@JackOfAllTrades, यदि विधि का एकमात्र उद्देश्य किसी बाहरी संसाधन से निपटना है, तो उस निर्भरता को इंजेक्ट करने वाला शायद ही कोई बिंदु हो। अन्यथा, यह एक समाधान हो सकता है (हालांकि बाद के मामले में, विधि शायद सिंगल रिस्पॉन्सिबिलिटी सिद्धांत को तोड़ देती है, इस प्रकार रिफ्लेक्टरिंग के लिए एक उम्मीदवार है)।
Péter Török

1
स्टैटिक्स आसानी से 'मॉकडाउन' हो जाते हैं - Microsoft मोल्स या फेक (निर्भर करता है, VS2010 या VS2012 +) आपको अपने परीक्षणों में अपने स्वयं के कार्यान्वयन के साथ एक स्थिर विधि को बदलने की अनुमति देता है। पुराने नकली ढांचे को अप्रचलित बनाता है। (यह पारंपरिक मॉक भी करता है, और साथ ही ठोस कक्षाओं का भी मज़ाक उड़ा सकता है)। विस्तार प्रबंधक के माध्यम से एमएस से मुक्त।
gbjbaanb

4

जिसे आप अपने कोड में करना पसंद करते हैं

मैं # 1 ( this->DoSomethingWithBarImpl();) पसंद करता हूं , जब तक कि सहायक विधि को उदाहरण के डेटा / कार्यान्वयन तक पहुंच की आवश्यकता नहीं होती है static t_image OpenDefaultImage()

और ऐसा करने के लिए आपके कारण क्या हैं?

सार्वजनिक इंटरफ़ेस और निजी कार्यान्वयन और सदस्य अलग-अलग हैं। अगर मैं # 2 का विकल्प चुनूं तो प्रोग्राम पढ़ना ज्यादा मुश्किल होगा। # 1 के साथ, मेरे पास हमेशा सदस्य और उदाहरण उपलब्ध हैं। कई OO आधारित कार्यान्वयनों की तुलना में, मैं बहुत अधिक इनकैप्सुलेशन, और प्रति वर्ग बहुत कम सदस्यों का उपयोग करता हूं। जहां तक ​​साइड इफेक्ट्स की बात है - मैं इसके साथ ठीक हूं, अक्सर राज्य सत्यापन होता है जो निर्भरता बढ़ाता है (उदाहरण के लिए किसी को पास करने की आवश्यकता होगी)।

# पढ़ने, बनाए रखने और अच्छा प्रदर्शन करने के लिए बहुत सरल है। बेशक, ऐसे मामले होंगे जहां आप एक कार्यान्वयन साझा कर सकते हैं:

static void ValidateImage(const t_image& image);
void validateImages() const {
    ValidateImage(this->innerImage());
    ValidateImage(this->outerImage());
}

यदि कोडबेस में # 2 एक अच्छा सामान्य समाधान (जैसे डिफ़ॉल्ट) था, तो मुझे डिज़ाइन की संरचना के बारे में चिंतित होना चाहिए: क्या कक्षाएं बहुत अधिक कर रही हैं? क्या पर्याप्त एनकैप्सुलेशन नहीं है या पर्याप्त पुन: उपयोग नहीं है? अमूर्त स्तर काफी अधिक है?

अंत में, # 2 बेमानी लगता है यदि आप OO भाषाओं का उपयोग कर रहे हैं जहाँ उत्परिवर्तन समर्थित है (उदाहरण के लिए एक constविधि)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.