जावा - क्या पूरी तरह से स्थिर वर्गों का होना एक बुरा विचार है?


16

मैं अभी एक बड़ी एकल परियोजना पर काम कर रहा हूं, और मेरे पास कई कक्षाएं हैं जिनमें मुझे कोई उदाहरण नहीं दिखता है।

मेरा पासा वर्ग अभी, उदाहरण के लिए, अपने सभी डेटा को सांख्यिकीय रूप से संग्रहीत करता है और इसके सभी तरीके स्थिर भी हैं। मुझे इसे शुरू करने की आवश्यकता नहीं है क्योंकि जब मैं पासा को रोल करना चाहता हूं और एक नया मूल्य प्राप्त करना चाहता हूं, तो मैं उपयोग करता हूं Dice.roll()

मेरे पास कई समान कक्षाएं हैं जिनमें केवल एक ही मुख्य कार्य है और मैं एक "नियंत्रक" वर्ग पर काम करना शुरू करने वाला हूं जो सभी घटनाओं के प्रभारी होंगे (जैसे जब कोई खिलाड़ी चलता है, और क्या चालू होता है यह है) और मैंने पाया है कि मैं इस वर्ग के लिए एक ही विचार का पालन कर सकता हूं। मैं कभी भी इन विशिष्ट वर्गों के लिए कई ऑब्जेक्ट्स बनाने की योजना नहीं बनाता, इसलिए उन्हें पूरी तरह से स्थिर बनाने के लिए एक बुरा विचार होगा?

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


1
यदि आपका कार्यक्रम पूरी तरह से प्रक्रियात्मक है। आपने जावा क्यों चुना?
Laiv

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

@Laiv मैं प्रोग्रामिंग के लिए अभी भी नई तरह का हूं, C ++ के एक साल के बारे में, मैं इस सेमेस्टर में जावा क्लास ले रहा हूं और मुझे जावा बहुत अधिक पसंद आने लगा है, खासकर ग्राफिक्स लाइब्रेरी।
HexTeke


5
स्टैटिक क्लासेस के बारे में। यदि स्थिर विधियाँ शुद्ध हैं (कोई स्थिति नहीं पकड़ते हैं, तो इनपुट तर्क और वापसी प्रकार हैं)। इस बारे में चिंतित होने की कोई बात नहीं है
Laiv

जवाबों:


20

स्थैतिक वर्गों के साथ कुछ भी गलत नहीं है जो वास्तव में स्थिर हैं । कहने का तात्पर्य यह है कि बोलने की कोई आंतरिक स्थिति नहीं है, जिससे तरीकों का उत्पादन बदल सके।

यदि Dice.roll()बस 1 से 6 तक एक नया रैंडम नंबर लौटा रहा है, तो यह राज्य नहीं बदल रहा है। दी, आप एक Randomउदाहरण साझा कर रहे हैं , लेकिन मैं यह नहीं समझूंगा कि परिभाषा के अनुसार राज्य का एक बदलाव, आउटपुट हमेशा अच्छा, यादृच्छिक होने वाला है। यह थ्रेड-सेफ भी है, इसलिए यहां कोई समस्या नहीं है।

आप अक्सर अंतिम "हेल्पर" या अन्य उपयोगिता कक्षाएं देखेंगे जिनमें एक निजी निर्माता और स्थिर सदस्य हैं। निजी कंस्ट्रक्टर में कोई तर्क नहीं होता है और केवल किसी को क्लास को तत्काल करने से रोकने के लिए कार्य करता है। अंतिम संशोधन केवल इस विचार को घर लाता है कि यह एक ऐसा वर्ग नहीं है जिसे आप कभी प्राप्त करना चाहते हैं। यह केवल एक उपयोगिता वर्ग है। यदि ठीक से किया जाता है, तो कोई एकल या अन्य वर्ग के सदस्य नहीं होने चाहिए जो स्वयं स्थिर और अंतिम न हों।

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


एक वर्ग के लिए राज्य में बदलाव को क्या माना जाता है ? ठीक है, एक दूसरे के लिए यादृच्छिक संख्या को बाहर करने की अनुमति देता है, क्योंकि वे परिभाषा द्वारा nondeterministic हैं और इसलिए वापसी मूल्य अक्सर बदलता रहता है।

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

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

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"

7
यदि मैं परीक्षण करना चाहता हूं कि एक डबल सिक्स रोल होने पर क्या होता है, तो मैं यहां फंस गया हूं क्योंकि आपके पास एक स्थिर यादृच्छिक संख्या जनरेटर के साथ स्थिर वर्ग है। तो नहीं, Dice.roll()"कोई वैश्विक राज्य" नियम के लिए एक वैध अपवाद नहीं है।
डेविड अरनो

1
@HexTeke अपडेट किया गया उत्तर।
नील

1
@DavidArno सच है, लेकिन मुझे लगता है कि अगर हम एक कॉल का परीक्षण कर रहे हैं तो हम वास्तव में मुसीबत में हैं random.nextInt(6) + 1। ;)
नील

3
@ नील, माफी, मैंने खुद को बहुत अच्छी तरह से नहीं समझाया। हम यादृच्छिक संख्या अनुक्रम का परीक्षण नहीं कर रहे हैं, हम अन्य परीक्षणों की सहायता के लिए उस अनुक्रम को प्रभावित कर रहे हैं। यदि हम परीक्षण कर रहे हैं कि उदाहरण के लिए RollAndMove()जब हम एक दोहरा छक्का लगाते हैं, तो सबसे आसान, सबसे मजबूत तरीका यह है कि Diceया तो रैंडम नंबर जनरेटर का मजाक उड़ाया जाए । एर्गो, Diceएक स्थिर यादृच्छिक जनरेटर का उपयोग करके स्थिर वर्ग नहीं बनना चाहता है।
डेविड अरनो

12
आपका अद्यतन इस मुद्दे को सिर पर मारता है: स्थैतिक विधियाँ नियतात्मक होनी चाहिए; उनका कोई दुष्प्रभाव नहीं होना चाहिए।
डेविड अरनो

9

एक staticवर्ग की सीमाओं का उदाहरण देने के लिए , क्या होगा यदि आपके कुछ गेमर्स अपने मरने वाले रोल पर मामूली बोनस प्राप्त करना चाहते हैं? और वे मोटी रकम देने को तैयार हैं! :-)

हां, आप एक और पैरामीटर जोड़ सकते हैं, इसलिए Dice.roll(bonus),

बाद में आपको डी 20 की जरूरत है।

Dice.roll(bonus, sides)

हाँ, लेकिन कुछ खिलाड़ियों के पास "सर्वोच्च रूप से सक्षम" करतब होते हैं, इसलिए वे कभी भी "विफल" नहीं होते (रोल 1)।

Dice.roll(bonus, sides, isFumbleAllowed)

यह गड़बड़ हो रहा है, है ना?


यह प्रश्न के लिए रूढ़िवादी प्रतीत होता है, इसकी गड़बड़ हो रही है कि क्या ये स्थिर तरीके या सामान्य तरीके हैं
jk।

4
@ जक, मुझे लगता है कि मैं उनकी बात समझ गया हूं। जब आप अधिक प्रकार के डाइस में सोचते हैं तो पासा स्टेटिक क्लास होने का कोई मतलब नहीं है। उस मामले में, हमारे पास अलग-अलग पासा ऑब्जेक्ट हो सकते हैं, उन्हें अच्छे ओओपी प्रथाओं के साथ मॉडलिंग कर सकते हैं।
धेरिक

1
@TimothyTruckle मैं विवादित नहीं हूं, सभी मैं कह रहा हूं कि यह जवाब वास्तव में सवाल का जवाब नहीं देता है, क्योंकि इस तरह की गुंजाइश रेंगने का इस विधि के स्थिर होने या न होने से कोई लेना-देना नहीं है।
nvoigt

2
@nvoigt "मैं विवादित नहीं हूं" - ठीक है, मैं करता हूं। OO भाषा की सबसे शक्तिशाली विशेषता बहुरूपता है । और स्थैतिक पहुंच प्रभावी रूप से हमें इसका उपयोग करने से रोकती है। और आप सही हैं: new Dice().roll(...)को स्थिर पहुँच के साथ-साथ संक्षिप्त होना चाहिए Dice.roll(...)। हम केवल तभी लाभान्वित होते हैं जब हम उस निर्भरता को इंजेक्ट करते हैं।
तीमुथियुस ट्रक

2
@ जेके अंतर यह है कि staticगड़बड़ हर कॉल में होती है, और हर कॉल में आवश्यक ज्ञान की आवश्यकता होती है, इसलिए यह आपके आवेदन पर विश्व स्तर पर विभाजित हो जाता है। एक OOP संरचना में, केवल निर्माणकर्ता / कारखाने को गड़बड़ करने की आवश्यकता होती है, और उस मरने के विवरणों को समझाया जाता है। उसके बाद, बहुरूपता का उपयोग करें और बस कॉल करें roll()। मैं स्पष्ट करने के लिए इस उत्तर को संपादित कर सकता हूं।
user949300

3

एक पासा वर्ग के विशेष मामले में मुझे लगता है कि स्टैटिक्स के बजाय उदाहरण के तरीकों का उपयोग करना परीक्षण को काफी आसान बना देगा।

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

मैं एक जावा डेवलपर नहीं हूं, लेकिन मुझे लगता है कि पूरी तरह से स्थिर पासा वर्ग के साथ ऐसा करना काफी कठिन होगा। Https://stackoverflow.com/questions/4482315/why-does-mockito-not-mock-static-methods देखें


सिर्फ रिकॉर्ड के लिए: जावा में हमारे पास बाइट कोड में हेरफेर करके स्थिर निर्भरता को बदलने के लिए पॉवरमॉक है। लेकिन इसका उपयोग करना केवल खराब डिज़ाइन के लिए एक आत्मसमर्पण है ...
टिमोथी ट्रकले

0

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

थोड़ा सा विषय: मैं शायद ही कभी VisualBasic में कीवर्ड्स के नामकरण से सहमत हूं, लेकिन इस मामले में, मुझे लगता sharedहै कि यह निश्चित रूप से स्पष्ट और शब्दार्थ से बेहतर है (यह खुद को और इसके सभी उदाहरणों के बीच साझा किया गया है) static(जीवनचक्र के बाद भी रहता है ) इसके दायरे की घोषणा की गई है।

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