2009-11-19 31 views
25

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

उत्तर

30

एक कारण है कि आप नहीं चाहते हैं कि यह स्थिर हो, इसे सबक्लास में ओवरराइड करने की अनुमति दी जाए। दूसरे शब्दों में, व्यवहार ऑब्जेक्ट के भीतर डेटा पर निर्भर नहीं हो सकता है, लेकिन ऑब्जेक्ट के सटीक प्रकार पर। उदाहरण के लिए, आपके पास isReadOnly संपत्ति के साथ एक सामान्य संग्रह प्रकार हो सकता है जो हमेशा-अप्रचलित संग्रह में false 0 -वापस लौटाएगा, true हमेशा-अपरिवर्तनीय संग्रह में, और दूसरों में आवृत्ति चर पर निर्भर करता है।

हालांकि, यह मेरे अनुभव में काफी दुर्लभ है - और आमतौर पर स्पष्टता के लिए स्पष्ट रूप से निर्दिष्ट किया जाना चाहिए। आम तौर पर मैं एक विधि बनाउंगा जो किसी ऑब्जेक्ट स्टेट स्टेटिक पर निर्भर नहीं है।

+1

@ डाउनवॉटर: एक कारण देने की देखभाल क्यों? –

+12

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

+2

कृपया मुझे वास्तव में मेरी टिप्पणी टाइप करने का समय छोड़ दें ;-) –

4

आप जो कहते हैं वह सच है, लेकिन क्या होता है जब आप व्युत्पन्न कक्षा में उस विधि के व्यवहार को ओवरराइड करना चाहते हैं? यदि यह स्थिर है, तो आप ऐसा नहीं कर सकते हैं।

class CustomerDAO { 
    public void CreateCustomer(Connection dbConn, Customer c) { 
     // Some implementation, created a prepared statement, inserts the customer record. 
    } 

    public Customer GetCustomerByID(Connection dbConn, int customerId) { 
     // Implementation 
    } 
} 

अब, उन तरीकों में से कोई भी किसी भी "राज्य" की आवश्यकता होती है:

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

के बाद से उन तरीकों स्थिर नहीं होते हैं, तो आप सिर्फ एक नया डीएओ वर्ग बना सकते हैं:

class OracleCustomerDAO : CustomerDAO { 
    public void CreateCustomer(Connection dbConn, Customer c) { 
     // Oracle specific implementation here. 
    } 

    public Customer GetCustomerByID(Connection dbConn, int customerId) { 
     // Oracle specific implementation here. 
    } 
} 

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

लेकिन अगर हमने उन तरीकों को स्थिर बना दिया है, जो चीजों को और अधिक जटिल बना देगा क्योंकि हम केवल एक नई कक्षा में स्थिर तरीकों को ओवरराइड नहीं कर सकते हैं।

+0

+1, यहां तक ​​कि स्टेटलेस विधियां भी एक उदाहरण से संबंधित हो सकती हैं, और ओवरराइड के लिए उपलब्ध हो सकती हैं। – erickson

0

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

21

सामान्य तौर पर, मैं निम्नलिखित कारणों के लिए उदाहरण के तरीकों को पसंद करते हैं: सुनिश्चित

  1. स्थिर तरीकों कठिन परीक्षण क्योंकि वे बदला नहीं जा सकता,
  2. स्थिर तरीकों को और अधिक प्रक्रियात्मक उन्मुख होते हैं।

मेरी राय में, स्थिरता विधियां उपयोगिता वर्गों (जैसे StringUtils) के लिए ठीक हैं, लेकिन मैं जितना संभव हो उतना उपयोग करने से बचाना पसंद करता हूं।

+2

+1 विशेष रूप से परीक्षण का उल्लेख करने के लिए। हम जुनीट का उपयोग कर रहे हैं, और नकली वस्तुओं में ओवरराइडिंग विधियों की आवश्यकता है। –

+12

2 के बारे में: ओओ एक उपकरण है, लक्ष्य नहीं। – erikkallen

+1

@erikkallen सहमत हुए। लेकिन जब मैं ओओ भाषा का उपयोग करता हूं, तो मुझे इस उपकरण का उपयोग करना पसंद है। –

0

जब आप उस कक्षा के किसी भी वस्तु से स्वतंत्र रूप से कक्षा के सदस्य का उपयोग करना चाहते हैं, तो इसे स्थैतिक घोषित किया जाना चाहिए।
यदि इसे स्थिर घोषित किया गया है तो इसे कक्षा के किसी ऑब्जेक्ट के मौजूदा उदाहरण के बिना एक्सेस किया जा सकता है। एक स्थिर सदस्य उस विशिष्ट वर्ग की सभी वस्तुओं द्वारा साझा किया जाता है।

40

सबसे बड़ी बुराइयों के दो क्या तुमने कभी बड़े पैमाने पर Java अनुप्रयोगों में सामना करेंगे

  • स्टेटिक तरीकों, उन है कि शुद्ध कार्यों *
  • परिवर्त्य स्थिर क्षेत्रों

ये बर्बाद कर रहे हैं को छोड़कर कर रहे हैं आपके कोड की मॉड्यूलरिटी, एक्स्टेंसिबिलिटी और टेस्टेबिलिटी एक डिग्री के लिए जो मुझे एहसास है, मैं संभवतः इस सीमित समय और स्थान में आपको मनाने की उम्मीद नहीं कर सकता।

* एक "शुद्ध कार्य" कोई भी विधि है जो किसी भी राज्य को संशोधित नहीं करती है और जिसका परिणाम कुछ भी नहीं बल्कि पैरामीटर प्रदान करता है। इसलिए, उदाहरण के लिए, कोई भी कार्य जो I/O (प्रत्यक्ष या परोक्ष रूप से) करता है वह एक शुद्ध कार्य नहीं है, लेकिन निश्चित रूप से Math.sqrt() है।

More blahblah about pure functions (स्वयं-लिंक) और आप उनसे क्यों रहना चाहते हैं।

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

+2

तो आप किसी स्थिर विधि के भीतर किसी भी I/O को करने के खिलाफ बहस करेंगे, भले ही यह ऑब्जेक्ट की स्थिति के साथ कुछ भी न करे, यह एक मुहरबंद वर्ग है, और आप ऑब्जेक्ट में गुज़र रहे हैं जिस पर आईओ को तर्क के रूप में निष्पादित करना है ? मैं मानता हूं कि यह अभी भी शुद्ध नहीं होगा, लेकिन मुझे नहीं लगता कि यह इस मामले में एक उदाहरण विधि कैसे मदद करता है। –

+1

(मैं म्यूटेबल स्थिर क्षेत्रों से आम तौर पर एक बुरा विचार मानता हूं, आपको दिमाग में रखता हूं।) –

+4

एक तरफ ध्यान दें, हर किसी के लिए: केविन के साथ असहमति व्यक्त करना एरिक लिपर्ट के साथ असहमति व्यक्त करना है। मैं घबराहट महसूस कर रहा हूं, लगभग एक विशाल cluestick के साथ सिर पर मारा जाने की उम्मीद है। कृपया नम्र हो, केविन ... –

0

स्थिर तरीकों के बारे में एक अतिरिक्त परेशानी: इसके आसपास एक रैपर वर्ग बनाने के बिना इस तरह के एक समारोह के संदर्भ में पास करने का कोई आसान तरीका नहीं है। जैसे - कुछ ऐसा:

FunctorInterface f = new FunctorInterface() { public int calc(int x) { return MyClass.calc(x); } }; 

मुझे इस तरह के जावा मेक-वर्क से नफरत है। हो सकता है कि जावा के बाद के संस्करण में प्रतिनिधियों या एक समान कार्य सूचक/प्रक्रियात्मक प्रकार तंत्र मिलेगा?

एक मामूली गड़बड़ी, लेकिन पर एक और चीज gratuitous स्थिर कार्य, er, विधियों के बारे में।

1

स्टेटिक विधियां आमतौर पर दो उद्देश्यों के लिए लिखी जाती हैं। पहला उद्देश्य java.util.Collections में मिली कार्यक्षमता के समान कुछ प्रकार की वैश्विक उपयोगिता विधि है। ये स्थैतिक विधियां आम तौर पर हानिरहित होती हैं। दूसरा उद्देश्य ऑब्जेक्ट इंस्टेंटेशन को नियंत्रित करना और singletons और factories जैसे विभिन्न डिज़ाइन पैटर्न के माध्यम से संसाधनों (जैसे डेटाबेस कनेक्शन) तक पहुंच सीमित करना है। ये खराब हो सकते हैं, परिणामस्वरूप समस्याएं हो सकती हैं।

  1. वे कोड कम मॉड्यूलर है और कठिन परीक्षण/विस्तार करने के लिए करते हैं:

    मेरे लिए, वहाँ स्थिर तरीकों का उपयोग कर के लिए दो कमियां हैं। अधिकांश उत्तरों ने पहले ही इसे संबोधित किया है, इसलिए मैं इसमें और नहीं जाऊंगा।

  2. स्टेटिक विधियों का परिणाम वैश्विक राज्य के कुछ रूपों में होता है, जो अक्सर कपटपूर्ण बग का कारण होता है। यह खराब लिखित कोड में हो सकता है जो ऊपर वर्णित दूसरे उद्देश्य के लिए लिखा गया है। मुझे विस्तार से बताएं।

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

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

इन समस्याओं से दूर होने के लिए, डेवलपर्स को स्थिर विधियों और चर के माध्यम से किसी भी राज्य को संग्रहित करने से बचना चाहिए। इसके बजाए, उन्हें स्वच्छ एपीआई बनाना चाहिए जो उपयोगकर्ताओं को आवश्यकतानुसार राज्य को प्रबंधित और अलग कर दें। BerkeleyDB यहां एक अच्छा उदाहरण है, स्थिर कॉल के माध्यम से Environment ऑब्जेक्ट के माध्यम से राज्य को encapsulating।

+0

यह स्थैतिक राज्य के खिलाफ एक बहुत ही सुसंगत तर्क है, लेकिन सामान्य रूप से स्थैतिक तरीकों के खिलाफ नहीं। मैं लिखने वाली सबसे स्थिर विधियां केवल उनके पैरामीटर का उपयोग करती हैं। माना जाता है कि मैं स्थैतिक लॉगर चर का उपयोग करता हूं, जो मुझे सहमत है ... –

+0

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

0

यहां दो प्रश्न 1) ऑब्जेक्ट्स बनाने वाली एक स्थिर विधि पहली बार एक्सेस होने पर स्मृति में लोड होती है? क्या यह (स्मृति में लोड शेष) एक कमी है? 2) जावा का उपयोग करने के फायदों में से एक इसकी कचरा संग्रह सुविधा है - क्या हम स्थिर तरीकों का उपयोग करते समय इसे अनदेखा नहीं कर रहे हैं?

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