क्या 'यूटील ’कक्षाएं चिंता का कारण हैं? [बन्द है]


14

मैं कभी-कभी 'यूटिल' कक्षाएं बनाता हूं जो मुख्य रूप से उन तरीकों और मूल्यों को रखने के लिए काम करती हैं जो वास्तव में कहीं और नहीं लगते हैं। लेकिन हर बार जब मैं इनमें से एक वर्ग बनाता हूं, तो मुझे लगता है कि "उह-ओह, मुझे बाद में पछतावा होगा ...", क्योंकि मैंने कहीं पढ़ा है कि यह बुरा है।

लेकिन दूसरी ओर, उनके लिए दो सम्मोहक (कम से कम मेरे लिए) मामले प्रतीत होते हैं:

  1. कार्यान्वयन रहस्य जो एक पैकेज में कई वर्गों में उपयोग किए जाते हैं
  2. अपने इंटरफेस को अव्यवस्थित किए बिना, एक वर्ग को बढ़ाने के लिए उपयोगी कार्यक्षमता प्रदान करना

क्या मैं विनाश के रास्ते पर हूँ? क्या आप कहते हैं !! क्या मुझे रिफलेक्टर करना चाहिए?


11
Utilअपनी कक्षाओं के नामों का उपयोग करना बंद करें। समस्या सुलझ गयी।
यानिस y

3
@MattFenwick Yannis के पास एक अच्छा बिंदु है। एक वर्ग का नामकरण SomethingUtilथोड़ा आलसी है और सिर्फ वर्ग के वास्तविक उद्देश्य को धुंधला कर देता है - नामित वर्गों के साथ एक ही SomethingManagerया SomethingService। यदि उस वर्ग की एक ही जिम्मेदारी है, तो उसे एक सार्थक नाम देना आसान होना चाहिए। यदि नहीं, तो इससे निपटने के लिए वास्तविक समस्या है ...
मैटाडेवी

1
@MDavey अच्छा बिंदु, यह शायद एक बुरा शब्द का उपयोग करने के लिए विकल्प था Util, हालांकि स्पष्ट रूप से मुझे उम्मीद नहीं थी कि उस पर ठीक हो जाएगा और बाकी के सवाल को नजरअंदाज कर दिया ...

1
यदि आप एक से अधिक * यूटील कक्षाएं बनाते हैं, तो वे किस प्रकार की वस्तु से अलग हो जाते हैं, तो मुझे लगता है कि यह ठीक है। मैं एक स्ट्रिंग, सूची, आदि के साथ कोई समस्या नहीं देख रहा हूँ, जब तक आप C # में नहीं हैं, तब आपको extention विधियों का उपयोग करना चाहिए।
मार्को-फ़िसेट

4
मेरे पास अक्सर ऐसे फ़ंक्शन होते हैं जो संबंधित उद्देश्यों के लिए उपयोग किए जाते हैं। वे वास्तव में एक वर्ग के लिए अच्छी तरह से मैप नहीं करते हैं। मुझे एक ImageResizer वर्ग की आवश्यकता नहीं है, मुझे बस एक ResizeImage फ़ंक्शन की आवश्यकता है। तो मैं संबंधित कार्यों को इमेजटूल जैसे स्थिर वर्ग में रखूंगा। ऐसे कार्यों के लिए जो अभी तक किसी भी प्रकार के समूह में नहीं हैं, मेरे पास उन्हें धारण करने के लिए एक यूटील स्टैटिक क्लास है, लेकिन एक बार मेरे पास कुछ ऐसे हैं जो एक वर्ग में फिट होने के लिए एक-दूसरे से संबंधित हैं, तो मैं उन्हें स्थानांतरित करूँगा। मैं इसे संभालने के लिए कोई बेहतर OO तरीका नहीं देखता।
फिलिप

जवाबों:


26

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

जावा और सी # (और अन्य) आपको एक उपयोग वर्ग बनाने और इसे करने के लिए उस घेरा से कूदने की आवश्यकता है। कष्टप्रद, लेकिन दुनिया का अंत नहीं; और वास्तव में एक डिजाइन के नजरिए से परेशान नहीं है।


हाँ, यह वही है जो मैं सोच रहा था। जवाब के लिए धन्यवाद!

सहमत, हालांकि यह उल्लेख किया जाना चाहिए कि .NET अब इस दृष्टिकोण के विकल्प के रूप में विस्तार के तरीकों और आंशिक कक्षाओं की पेशकश करता है। यदि आप इस आइटम को इसके चरम पर ले जाते हैं, तो आप रूबी मिश्रण के साथ समाप्त होते हैं - एक ऐसी भाषा जिसकी उपयोगिता वर्गों के लिए बहुत कम आवश्यकता है।
neontapir

2
@neontapir - विस्तार विधियों के कार्यान्वयन को छोड़कर मूल रूप से आपको विस्तार विधियों के साथ एक उपयोग वर्ग बनाने के लिए मजबूर किया जाता है ...
Telastyn

सच। दो जगह हैं जहां यूटील कक्षाएं बाधा डालती हैं, एक कक्षा में ही है और दूसरा कॉलसाइट है। विधियों को देखने से ऐसा लगता है जैसे वे बढ़ी हुई वस्तु पर मौजूद हैं, विस्तार विधियां कॉलिट समस्या को संबोधित करती हैं। मैं मानता हूं, अभी भी यूटील वर्ग की मौजूदगी का मुद्दा है।
22

16

नेवर से नेवर"

मुझे नहीं लगता कि यह आवश्यक रूप से बुरा है, यह केवल बुरा है यदि आप इसे बुरी तरह से करते हैं और इसका दुरुपयोग करते हैं।

वी ऑल नीड टूल्स एंड यूटिलिटीज

शुरुआत के लिए, हम सभी कुछ पुस्तकालयों का उपयोग करते हैं जिन्हें कभी-कभी लगभग सर्वव्यापी और मस्तूल के रूप में समझा जाता है। उदाहरण के लिए, जावा दुनिया में, Google Guava या Apache Commons ( Apache Commons Lang , Apache Commons Collections , etc ...)।

अतः स्पष्ट रूप से इनकी आवश्यकता है।

हार्ड-वर्ड, डुप्लीकेशन और इंट्रोड्यूसिंग बग्स से बचें

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

तो मैं कहूंगा कि जब Utilकक्षा लिखने के लिए खुजली महसूस होती है तो अंगूठे का पहला नियम यह जांचना है कि Utilवास्तव में कक्षा पहले से मौजूद नहीं है।

इसके लिए मैंने जो एकमात्र प्रतिवाद देखा है, वह तब है जब आप अपनी निर्भरता को सीमित करना चाहते हैं क्योंकि:

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

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

इसलिए, यदि यह एक देयता में है और आपके उपयोग के मामले से मेल खाता है, और कोई भी बेंचमार्क आपको अन्यथा नहीं बताता है, तो इसका उपयोग करें। यदि यह आपके द्वारा थोड़े से भिन्न होता है, तो इसे बढ़ाएं (यदि संभव हो) या इसे बढ़ाएं, या अंतिम उपाय में इसे फिर से लिखें।

नामकरण की परंपरा

हालाँकि, अब तक इस उत्तर में मैंने उन्हें अपने Utilजैसा कहा है । उनका नाम मत लो।

उन्हें सार्थक नाम दें। Google अमरूद को एक (बहुत, बहुत) अच्छे उदाहरण के रूप में लें कि क्या करना है, और बस कल्पना करें कि com.google.guavaनाम स्थान वास्तव में आपकी utilजड़ है।

अपने पैकेज को कॉल करें util, कम से कम, लेकिन कक्षाओं को नहीं। यदि Stringस्ट्रिंग निर्माण की वस्तुओं और हेरफेर से संबंधित है, तो इसे कॉल करें Strings, नहीं StringUtils(क्षमा करें, अपाचे कॉमन्स लैंग - मैं अभी भी और आपको उपयोग करता हूं!)। यदि यह कुछ विशिष्ट करता है, तो एक विशिष्ट वर्ग नाम (जैसे Splitterया Joiner) चुनें।

अध्याय परीक्षा

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

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

एपीआई डिजाइन

इन APIs के लिए आपके द्वारा लिया गया डिज़ाइन निर्णय, संभवतः लंबे समय तक आपका अनुसरण करेगा। इसलिए, एक Splitter-क्लोन लिखने पर घंटों खर्च नहीं करते हैं , तो इस बारे में सावधान रहें कि आप इस मुद्दे पर कैसे दृष्टिकोण रखते हैं।

अपने आप से कुछ सवाल पूछें:

  • क्या आपकी उपयोगिता विधि अपने आप ही एक वर्ग का वारंट करती है, या एक स्थिर विधि काफी अच्छी है, अगर यह समान उपयोगी तरीकों के समूह का हिस्सा बनने के लिए समझ में आता है?
  • क्या आपको ऑब्जेक्ट बनाने और अपने API को अधिक पठनीय बनाने के लिए फ़ैक्टरी विधियों की आवश्यकता है ?
  • पठनीयता की बात करें तो क्या आपको धाराप्रवाह एपीआई , बिल्डरों आदि की आवश्यकता है ...?

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

हमेशा की तरह, यहाँ दिग्गजों से सीखें:

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


+1 के लिएIf deals with String objects and manipulation of string constructs, call it Strings, not StringUtils
तुलसी कोर्डोवा

+1 .Net में API डिज़ाइन के लिए, .Net के वास्तुकारों द्वारा पुस्तक पढ़ें। फ्रेमवर्क डिजाइन दिशानिर्देश: कन्वेंशन, मुहावरे, और पुन: प्रयोज्य .NET पुस्तकालयों के लिए पैटर्न
MarkJ

आप इसे स्ट्रींग यूटिल (एस) के बजाय स्ट्रिंग्स क्यों कहेंगे? मुझे स्ट्रिंग्स एक संग्रह वस्तु की तरह लगता है।
bdrx

@bdrx: StringsCollectionTypeHereयदि आप एक ठोस कार्यान्वयन चाहते हैं तो मेरे लिए एक संग्रह वस्तु होगी । या अधिक विशिष्ट नाम अगर इन तार का आपके ऐप के संदर्भ में विशिष्ट अर्थ है। इस विशेष मामले के लिए, अमरूद Stringsस्ट्रिंग-संबंधित सहायकों के लिए उपयोग करता है , जैसा कि StringUtilsकॉमन्स लैंग में विरोध किया गया है। मुझे यह पूरी तरह से स्वीकार्य लगता है, मेरे लिए बस इसका मतलब है कि कक्षाएं Stringऑब्जेक्ट को संभालती हैं या स्ट्रिंग्स का प्रबंधन करने के लिए एक सामान्य उद्देश्य वर्ग है।
ज्येष्ठ

@bdrx: सामान्य NameUtilsसामान बग में मुझे कोई अंत नहीं है क्योंकि अगर यह एक स्पष्ट रूप से लेबल पैकेज नाम के तहत बैठता है, तो मुझे पहले से ही पता होगा कि यह एक उपयोगिता वर्ग है (और यदि नहीं, तो यह एपीआई को देखने से जल्दी पता लगाएगा)। यह लोगों के रूप में सामान की घोषणा के रूप में मेरे लिए कष्टप्रद के रूप में है SomethingInterface, ISomethingया SomethingImpl। जब सी में कोडिंग और आईडीई का उपयोग नहीं कर रहा था तो मैं इस तरह के कलाकृतियों के साथ ठीक था। आज मुझे आमतौर पर ऐसी चीजों की कोई आवश्यकता नहीं होती।
ज्येष्ठ

8

यूटील क्लासेस कॉइसेक्टिव नहीं होते हैं और आम तौर पर खराब डिजाइन होते हैं क्योंकि एक क्लास को बदलने का एक ही कारण होता है (सिंगल रिस्पांसिबिलिटी प्रिंसिपल)।

फिर भी, मैंने देखा है की तरह बहुत जावा एपीआई में कक्षाएं, "util": Math, Collectionsऔर Arrays

ये वास्तव में, उपयोगिता वर्ग हैं लेकिन उनके सभी तरीके एक ही विषय से संबंधित हैं, एक में गणितीय संचालन हैं, एक में संग्रह में हेरफेर करने के लिए और दूसरे में हेरफेर के लिए तरीके हैं।

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

यदि उपयोग की हुई कक्षाएं होनी चाहिए, तो उन्हें जावा Math, Collectionsऔर जैसे विषय से अलग करने का प्रयास करेंArrays । यह कम से कम, डिजाइन के कुछ इरादे दिखाता है, तब भी जब वे सिर्फ नामस्थान होते हैं।

मैं एक के लिए, हमेशा उपयोगिता वर्गों से बचता हूं और कभी भी एक बनाने की आवश्यकता नहीं रही है ।


जवाब के लिए धन्यवाद। इसलिए, भले ही उपयोग कक्षाएं पैकेज-निजी हों, वे अभी भी एक डिज़ाइन गंध हैं?

हालांकि सब कुछ एक वर्ग में नहीं है। यदि आपकी भाषा किसी ऐसी भाषा के साथ अटकी हुई है जो जोर देकर कहती है कि यह तब होता है तो कक्षाएँ होंगी।
जे.के.

1
ठीक है, उपयोगिता वर्गों में डिज़ाइन सिद्धांत नहीं होता है ताकि आपको पता चल सके कि कितने तरीके बहुत अधिक हैं, क्योंकि शुरू करने के लिए कोई सामंजस्य नहीं है। आप कैसे जान सकते हैं कि कैसे रोकें? 30 तरीकों के बाद? 40? 100? ओओपी सिद्धांत, दूसरे हाथ में आपको एक विचार देते हैं कि कोई विधि किसी विशेष वर्ग से संबंधित नहीं है, और जब कक्षा बहुत अधिक कर रही है। इसे सामंजस्य कहा जाता है। लेकिन जैसा कि मैंने आपको अपने उत्तर में बताया था, जिन लोगों ने जावा डिज़ाइन किया था, वे उपयोगिता वर्ग का उपयोग करते थे। तुम भी नहीं कर सकते। मैं उपयोगिता वर्ग नहीं बनाता हूं और ऐसी स्थिति में नहीं आया हूं जब कोई चीज सामान्य वर्ग में नहीं होती है।
तुलसी कोर्डोवा

1
बर्तन कक्षाएं आमतौर पर वे कक्षाएं नहीं होती हैं जो वे केवल नामस्थान होती हैं जिनमें आमतौर पर शुद्ध, फ़ंक्शंस का एक गुच्छा होता है। शुद्ध कार्य उतने ही सामंजस्यपूर्ण हैं जितने आप पा सकते हैं।
जे.के.

1
@ जेके मेरा मतलब था यूटिल्स ... वैसे तो कम से कम डिज़ाइन के कुछ इरादों जैसे नामों के साथ आने Mathया Arraysदिखाने का।
टुल्लेंस कोर्डोवा

3

यह पूरी तरह से करने के लिए स्वीकार्य है util , कक्षाएं हालांकि मैं अवधि को पसंद करते ClassNameHelper। .NET BCL में भी सहायक कक्षाएं हैं। याद रखने वाली सबसे महत्वपूर्ण बात यह है कि कक्षाओं के उद्देश्य, साथ ही साथ प्रत्येक व्यक्ति सहायक विधि को अच्छी तरह से प्रलेखित करना और इसे उच्च गुणवत्ता बनाए रखने वाला कोड बनाना है।

और सहायक वर्गों के साथ दूर मत जाओ।


0

मैं दो स्तरीय दृष्टिकोण का उपयोग करता हूं। एक "उपयोग" पैकेज (फ़ोल्डर) में एक "ग्लोबल्स" वर्ग। "ग्लोबल्स" श्रेणी या "उपयोग" पैकेज में जाने के लिए कुछ के लिए, यह होना चाहिए:

  1. सरल,
  2. अपरिवर्तनीय,
  3. आपके आवेदन में किसी और चीज़ पर निर्भर नहीं

इन परीक्षणों को पास करने वाले उदाहरण:

  • सिस्टम-वाइड दिनांक और दशमलव स्वरूप
  • अपरिवर्तनीय वैश्विक डेटा, जैसे EARLIEST_YEAR (जो सिस्टम समर्थन करता है) या IS_TEST_MODE या कुछ-ऐसे सही मायने में वैश्विक और अपरिवर्तनीय (सिस्टम चल रहा है) मान।
  • बहुत छोटे सहायक तरीके जो आपकी भाषा, फ्रेमवर्क या टूलकिट में अंतराल के आसपास काम करते हैं

यहाँ एक बहुत छोटी सहायक विधि का उदाहरण दिया गया है, जो बाकी के अनुप्रयोग से पूरी तरह से स्वतंत्र है:

public static String ordinal(final int i) {
    return (i == 1) ? "1st" :
           (i == 2) ? "2nd" :
           (i == 3) ? "3rd" :
           new StringBuilder().append(i).append("th").toString();
}

इसे देखते हुए मैं एक बग देख सकता हूं कि 21 को "21 वां" होना चाहिए, 22 को "22 वां" होना चाहिए, आदि लेकिन वह बिंदु के बगल में है।

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

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

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