'उपयोगिता फ़ंक्शंस' की कक्षाओं को टैम करना


15

हमारे जावा कोडबेस में मैं निम्नलिखित पैटर्न देखता हूं:

/**
 This is a stateless utility class
 that groups useful foo-related operations, often with side effects.
*/
public class FooUtil {
  public int foo(...) {...}
  public void bar(...) {...}
}

/**
 This class does applied foo-related things.
*/
class FooSomething {
  int DoBusinessWithFoo(FooUtil fooUtil, ...) {
    if (fooUtil.foo(...)) fooUtil.bar(...);
  }
}

मुझे परेशान करता है कि मुझे FooUtilहर जगह एक उदाहरण देना होगा , क्योंकि परीक्षण।

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

मुझे लगता है कि मेरा सबसे अच्छा शर्त इंजेक्शन का उपयोग करना है (और मैं करता हूं), लेकिन यह परेशानियों के अपने सेट को जोड़ता है। इसके अलावा, कई उपयोग उदाहरणों को पारित करने से विधि पैरामीटर सूचियों का आकार बढ़ जाता है।

क्या इसे बेहतर तरीके से संभालने का कोई तरीका है जो मैं नहीं देख रहा हूं?

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


4
और आपकी यह धारणा कि इकाई परीक्षण को प्रभावी ढंग से करने के लिए सभी निर्भरताओं का मज़ाक उड़ाया जाना सही नहीं है (हालाँकि मैं अभी भी उस प्रश्न की तलाश में हूँ जो उस पर चर्चा करता है)।
तेलस्तीन

4
ये तरीके उस वर्ग के सदस्य क्यों नहीं हैं जिनके डेटा में वे हेरफेर करते हैं?
जूल्स

3
जुनिट का एक अलग सेट है जो स्थैतिक धब्बों को बुलाता है अगर FooUtility है। फिर आप इसे बिना मॉकिंग के इस्तेमाल कर सकते हैं। यदि इसकी कुछ ऐसी चीज जो आपको मजाक बनाने की आवश्यकता है, तो मुझे इसकी न केवल एक उपयोगिता पर संदेह है, बल्कि कुछ IO या व्यावसायिक तर्क करना चाहिए और वास्तव में एक वर्ग के सदस्य का संदर्भ होना चाहिए और इसे कंस्ट्रक्टर, इनिट या सेटर विधि के माध्यम से प्रारंभ किया जाना चाहिए।
tgkprog

2
जूल्स टिप्पणी के लिए +1। यूटील क्लासेस एक कोड गंध हैं। शब्दार्थ के आधार पर एक बेहतर समाधान होना चाहिए। हो सकता है कि FooUtilतरीकों को डाल दिया जाए FooSomething, हो सकता है FooSomethingकि वहाँ के गुणों को बदल दिया जाए / बढ़ाया जाए ताकि FooUtilतरीकों की अब और ज़रूरत न हो। कृपया हमें FooSomethingइस सवाल का एक अच्छा जवाब प्रदान करने में मदद करने के लिए और अधिक ठोस उदाहरण दें।
वालेंट्री

13
@valenterry: केवल कारण उपयोग कक्षाएं एक कोड गंध हैं क्योंकि जावा स्टैंडअलोन कार्यों के लिए एक अच्छा तरीका प्रदान नहीं करता है। कार्यों के लिए बहुत अच्छे कारण हैं जो कक्षाओं के लिए विशिष्ट नहीं हैं।
रॉबर्ट हार्वे

जवाबों:


16

सबसे पहले मैं यह बता दूं कि विभिन्न समस्याओं के लिए अलग-अलग प्रोग्रामिंग दृष्टिकोण हैं। अपनी नौकरी के लिए मैं ऑर्गिनाज़ेशन और रखरखाव के लिए एक मजबूत ओओ डिज़ाइन पसंद करता हूं और मेरा जवाब यह दर्शाता है। एक कार्यात्मक दृष्टिकोण का बहुत अलग उत्तर होगा।

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

जब आपके पास एक संग्रह होता है जो आप चारों ओर से गुजर रहे होते हैं, तो ऐसा कोड होना चाहिए जो उस संग्रह का हिस्सा बनना चाहता है, और यह आपके पूरे सिस्टम में छिड़का जा रहा है और अंततः उपयोगिता कक्षाओं में एकत्र किया गया है।

मेरा सुझाव है कि अपने संग्रह (या बीन्स) को किसी भी अन्य संबंधित डेटा के साथ नई कक्षाओं में लपेटें और वास्तविक वस्तुओं में "उपयोगिता" कोड डालें।

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

यह "रैपिंग" किसी भी सामान्य प्रयोजन के पुस्तकालय ऑब्जेक्ट्स के लिए उपयोगी है जो डेटा रखता है लेकिन आप कोड को जोड़ नहीं सकते हैं - कोड को उस डेटा के साथ डालना जो इसे हेरफेर करता है OO डिजाइन में एक अन्य प्रमुख अवधारणा है।

ऐसे कई कोडिंग स्टाइल हैं जहां यह रैपिंग कॉन्सेप्ट एक बुरा आइडिया होगा - जो चाहते हैं कि एक बार की स्क्रिप्ट या टेस्ट को लागू करते समय पूरी क्लास लिखी जाए? लेकिन मुझे लगता है कि किसी भी मूल प्रकार / संग्रह का एनकैप्सुलेशन जो आप अपने आप में कोड नहीं जोड़ सकते हैं, ओओ के लिए अनिवार्य है।


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


@Deduplicator प्रोग्रामिंग के 40 वर्षों में मैंने शायद ही कभी (कभी भी) उस मामले को देखा है जहां मैं अप्रत्यक्ष के कई स्तरों द्वारा अवरुद्ध किया गया था (एक इंटरफ़ेस के बजाय कार्यान्वयन के लिए कूदने के लिए मेरी आईडीई के साथ सामयिक लड़ाई से अलग है) लेकिन मैं ' अक्सर (बहुत बार) ने उस मामले को देखा जहां लोगों ने स्पष्ट रूप से आवश्यक वर्ग बनाने के बजाय भयानक कोड लिखा था। हालांकि मेरा मानना ​​है कि बहुत अधिक अप्रत्यक्ष लोगों ने कुछ लोगों को काट लिया होगा, मैं उचित OO सिद्धांतों के पक्ष में त्रुटि करूँगा, जैसे कि प्रत्येक वर्ग एक काम अच्छी तरह से करना, उचित नियंत्रण, आदि
बिल K

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

@Deduplicator 'उपयोगिता' कार्य लिखते समय जो विशिष्ट व्यावसायिक आवश्यकताओं के बाहर लिखा जाना चाहिए, आप सही हैं। फ़ंक्शंस से भरी उपयोगिता कक्षाएं (जैसे संग्रह) ओओ में केवल अजीब हैं क्योंकि वे डेटा से जुड़े नहीं हैं। ये "एस्केप हैच" हैं जो लोग ओओ उपयोग के साथ सहज नहीं हैं (साथ ही, उपकरण विक्रेताओं को बहुत सामान्य कार्यक्षमता के लिए इनका उपयोग करना चाहिए)। ऊपर मेरा सुझाव था कि जब आप व्यावसायिक तर्क पर काम कर रहे हों तो इन हैक्स को कक्षाओं में लपेटें ताकि आप अपने डेटा के साथ अपने कोड को फिर से जोड़ सकें।
बिल के

1

आप एक प्रदाता पैटर्न का उपयोग कर सकते हैं और FooSomethingएक FooUtilProviderऑब्जेक्ट के साथ अपना इंजेक्षन कर सकते हैं (एक कंस्ट्रक्टर में हो सकता है; केवल एक बार)।

FooUtilProviderकेवल एक ही विधि होगा: FooUtils get();। वर्ग तब जो भी FooUtilsउदाहरण प्रदान करता है उसका उपयोग करेगा ।

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

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