2010-03-17 9 views
18

यहां मेरा नमूना सार सिंगलटन वर्ग है:मैं जावा में एक अमूर्त सिंगलटन कक्षा कैसे कार्यान्वित कर सकता हूं?

public abstract class A { 
    protected static A instance; 
    public static A getInstance() { 
     return instance; 
    } 
    //...rest of my abstract methods... 
} 

और यहां ठोस कार्यान्वयन है:

public class B extends A { 
    private B() { } 
    static { 
     instance = new B(); 
    } 
    //...implementations of my abstract methods... 
} 

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

Class c = B.class; 
A.getInstance() - returns null; 

और यह

ClassLoader.getSystemClassLoader().loadClass("B"); 
A.getInstance() - return null; 

इन दोनों को ग्रहण डीबगर में चलाना स्थिर कोड कभी निष्पादित नहीं होता है। स्थैतिक कोड निष्पादित करने का एकमात्र तरीका यह है कि बी के कन्स्ट्रक्टर पर सार्वजनिक रूप से पहुंच को बदलना और इसे कॉल करना है।

मैं इन परीक्षणों को चलाने के लिए उबंटू 32 बिट पर सूर्य-जावा 6-जेरे का उपयोग कर रहा हूं।

उत्तर

19

सार सिंगलटन? मेरे लिए व्यवहार्य ध्वनि नहीं है। सिंगलटन पैटर्न को private कन्स्ट्रक्टर की आवश्यकता होती है और यह पहले से ही सबक्लासिंग असंभव बनाता है। आपको अपने डिजाइन पर पुनर्विचार करना होगा। Abstract Factory pattern विशेष उद्देश्य के लिए अधिक उपयुक्त हो सकता है।

+0

सिंगलटन में निजी कन्स्ट्रक्टर का उद्देश्य किसी और को तत्काल इसे रोकने के लिए है। मैंने इसे यहां हासिल कर लिया है - आप एक अमूर्त वर्ग को तुरंत चालू नहीं कर सकते हैं, और सबक्लास के पास एक निजी कन्स्ट्रक्टर है। – Simon

+0

यह सबक्लास को केवल अमूर्त होने के लिए मजबूर नहीं करता है और केवल एक निजी कन्स्ट्रक्टर है। – BalusC

+0

सिंगलटन एक निजी कन्स्ट्रक्टर _require_ नहीं है (सार्वजनिक प्रश्नकर्ता के साथ इस प्रश्न के समाधान के लिए मेरा जवाब देखें)। – ryvantage

4

A.getInstance() कभी भी व्युत्पन्न उदाहरण को कॉल नहीं करेगा क्योंकि यह स्थिर रूप से बाध्य है।

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

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

+0

A.getInstance() को व्युत्पन्न उदाहरण कॉल करने की आवश्यकता नहीं है, क्योंकि यह आवृत्ति चर लौटाता है। व्युत्पन्न उदाहरण (कक्षा बी) आवृत्ति चर सेट करता है। सिवाय इसके कि स्थैतिक कोड ब्लॉक नहीं चलाया जाता है। यदि मैं इसे ठीक नहीं कर सकता तो कारखाना पैटर्न मेरा एकमात्र विकल्प हो सकता है। – Simon

4

सिंगलेट्स की तरह हैं। सार विरासत पर जोर देता है जो संभवतः avoid यदि संभव हो तो आप अधिक से अधिक नहीं चाहते हैं। कुल मिलाकर मैं पुनर्विचार करूँगा यदि आप जो करने की कोशिश कर रहे हैं वह simplest possible way है, और यदि ऐसा है, तो एक कारखाने का उपयोग करना सुनिश्चित करें, न कि सिंगलटन (सिंगलटन unit tests में प्रतिस्थापित करने के लिए कुख्यात रूप से कठिन हैं जबकि कारखानों को आसानी से परीक्षण उदाहरणों को प्रतिस्थापित करने के लिए कहा जा सकता है)।

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

+0

+1 इंगित करने के लिए कि सिंगलेट एक विरोधी पैटर्न हैं। –

+1

सिंगलेट्स की जगह है लेकिन आप जो कुछ भी कर रहे हैं उसके लिए आम तौर पर बेहतर डिजाइन पैटर्न होते हैं। एक लॉग शायद सबसे अच्छा उदाहरण है जिसे मैं सिंगलटन के बारे में सोच सकता हूं - इस तरह आपको एक चर पारित करने की आवश्यकता नहीं है और इसे कहीं से भी एक्सेस कर सकते हैं। –

+0

इंजेक्शन के साथ एक लॉग बहुत बेहतर किया जा सकता है। एक सिंगलटन लॉग आपको आसानी से नहीं बता सकता कि रेखा किस वर्ग से आई थी, जबकि लॉग l = new log (this.getClass()) या इसके कुछ भिन्नताएं हो सकती हैं। इंजेक्शन के साथ यह सिर्फ @ इंजेक्ट लॉग या कुछ समान है। लॉगिंग के लिए भी एक सिंगलटन परीक्षण करना कठिन होता है। फिर एक सिंगलटन बस सबसे खराब विकल्प (लेकिन स्वीकार्य रूप से उपयोग करने योग्य) के बारे में है –

2

इसके अलावा समस्याओं दूसरों के लिए ही बताया है, होने A में instance क्षेत्र मतलब है कि आप केवल पूरे वीएम में एक सिंगलटन हो सकता है। आप भी हों:

public class C extends A { 
    private C() { } 
    static { 
     instance = new C(); 
    } 
    //...implementations of my abstract methods... 
} 

... तो जो भी की B या C पिछले लोड हो जाता है जीत जाएगा, और दूसरे सिंगलटन उदाहरण खो जाएगा।

यह चीजों को करने का एक बुरा तरीका है।

+0

धन्यवाद - और अन्य जिन्होंने एक ही बात कहा था। यह बताता है कि मेरी असली समस्या यह है कि मैं कैसे चुनता हूं कि मेरे इंटरफ़ेस के कई कार्यान्वयन में से कौन सा खुलासा करना चाहिए। फैक्टरी या फेकाडे जाने के अच्छे तरीकों की तरह दिखते हैं। – Simon

8

आपकी पोस्ट से ठीक है, भले ही यह स्पष्ट रूप से नहीं बताया गया हो, ऐसा लगता है कि आप अमूर्त वर्ग को दो अलग-अलग भूमिकाएं खेलना चाहते हैं। भूमिकाएँ हैं:

  • एक (सिंगलटन) सेवा कई substitutable कार्यान्वयन हो सकता है के लिए सार कारखाने भूमिका,
  • सेवा इंटरफ़ेस भूमिका,

प्लस आप चाहते हैं कक्षाओं के पूरे परिवार में सिंगलटन को 'सिंगलोननेस' लागू करने की सेवा, किसी कारण से सेवा आवृत्ति को कैश करने के लिए पर्याप्त नहीं है।

यह ठीक है।

कोई कहता है कि यह बहुत बुरा लगता है क्योंकि "चिंताओं को अलग करने का उल्लंघन करता है" और "सिंगलेट और यूनिट परीक्षण अच्छी तरह से नहीं जाते हैं"।

कोई और कहता है कि यह ठीक है- क्योंकि आप परिवार में सही बच्चों को तुरंत चालू करने की ज़िम्मेदारी देते हैं और समग्र रूप से अधिक धाराप्रवाह इंटरफ़ेस का पर्दाफाश करते हैं क्योंकि आपको किसी कारखाने के मध्यस्थता की आवश्यकता नहीं होती है जो किसी को प्रकट करने से कुछ और नहीं करता है स्थैतिक विधि

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

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

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

public abstract class A{ 
    public static A getInstance(){ 
     if (...) 
     return B.getInstance(); 
     return C.getInstance(); 
    } 

    public abstract void doSomething(); 

    public abstract void doSomethingElse(); 

} 

public class B extends A{ 
    private static B instance=new B(); 

    private B(){ 
    } 

    public static B getInstance(){ 
     return instance; 
    } 

    public void doSomething(){ 
     ... 
    } 
    ... 
} 

//do similarly for class C 

माता-पिता भी प्रतिबिंब का उपयोग कर सकते हैं।

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

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

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