2010-05-10 9 views
27

जावा में, मैं मार्कर इंटरफेस को परिभाषित करने में सक्षम होना चाहता हूं, जो स्थैतिक तरीकों को प्रदान करने के लिए मजबूर कार्यान्वयन करता है। उदाहरण के लिए, सरल पाठ क्रमांकन/deserialization के लिए मैं एक अंतरफलक है कि कुछ इस तरह देखा परिभाषित करने में सक्षम होना चाहते हैं:स्थिरता लागू करने के लिए इंटरफेस पर स्थिर तरीकों के विकल्प

public interface TextTransformable<T>{ 

    public static T fromText(String text); 

    public String toText(); 

हालांकि (के रूप में एक में बताया गया है के बाद से जावा में इंटरफेस स्थिर तरीकों को शामिल नहीं कर सकते हैं अन्य पदों/धागे की संख्या: here, here, और here इस कोड काम नहीं करता

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

नोट: हमारे मामले में हमारे प्राथमिक उपयोग-मामले में हमारे पास कई "मूल्य-वस्तु" प्रकार - enums, या अन्य ऑब्जेक्ट्स हैं जिनमें सीमित संख्या में मूल्य हैं, आमतौर पर उनके मूल्य से परे कोई राज्य नहीं लेते हैं, और जो हम हजारों बार एक सेकंड पार्स/डी-पार्स करते हैं, इसलिए वास्तव में उदाहरणों का पुन: उपयोग करने (जैसे फ्लोट, इंटेगर इत्यादि) और मेमोरी खपत/जीसी पर इसके प्रभाव की परवाह है

कोई विचार?

EDIT1: कुछ भ्रम की स्थिति को स्पष्ट करने के लिए - हम कई, विभिन्न वस्तुओं इस पैटर्न फिटिंग -really हम 2 अर्थ विज्ञान के साथ कॉल करने के लिए कुछ सुंदर के साथ आने की कोशिश कर रहे हैं: अनुबंध के रूप में

  • इंटरफेस - पहुँच की एकता (एक क्षमता के रूप में TextTransformable जैसे) उपवर्गों/कार्यान्वयन द्वारा
  • आवश्यकता कार्यान्वयन (जैसे उन्हें अपने स्वयं के परिवर्तन

लागू करने के लिए Ter में मजबूर फ्लाईवेट, कारखानों के लिए हमारे विचारों के एमएस - वे दोनों विकल्प हैं जिन्हें हमने माना है, वास्तव में हम यह देखने की कोशिश कर रहे हैं कि क्या हम जावाडॉक पर भरोसा करने के बावजूद कुछ और अधिक सुरुचिपूर्ण पा सकते हैं, "एक फैक्ट्री लागू करें और इसे प्रतिनिधि कॉल करें, या इसे सम्मेलन द्वारा XXX स्थान पर बेनकाब करें "

उत्तर

6

यह Flyweight के लिए वास्तव में उपयुक्त है। यह मूल रूप से आप statics के साथ पूरा करने की कोशिश कर रहे हैं। फ्लाईवेट ऑब्जेक्ट की सेवा कैसे करें ताकि आप उनमें से हजारों को न बनाएं, यहां कुछ विचार दिए गए हैं।

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

दूसरा यह है कि मूल्य प्रकार में एक तरीका है जो इसके कनवर्टर की सेवा कर सकता है। कुछ इस तरह:

public class ValueType { 
     public static final TextTransformable<ValueType> CONVERT = .... 
} 

और फिर इस तरह इसका इस्तेमाल:

ValueType value = ValueType.CONVERT.fromText(text); 

String text = ValueType.CONVERT.toText(value); 

अब जब कि लागू नहीं करता है कि सभी ValueType के एक ही तंत्र के माध्यम से उनके कन्वर्टर्स प्रदान करते हैं उस के लिए मैं तुम्हें एक कारखाने की जरूरत है किसी तरह की।

संपादित करें: मुझे लगता है कि मैं क्या आप एक कारखाने के बारे में असजीला लगता है पता नहीं है, लेकिन मुझे लगता है कि आप कॉल करने पर ध्यान केंद्रित कर रहे हैं, तो कैसे आप को यह महसूस करता है:

ValueType value = getTransformer(ValueType.class).fromText(text); 

ऊपर किया जा सकता है कारखाने के एक स्थिर आयात और एक विधि इतनी तरह एक हस्ताक्षर है कि साथ:

public static <T> TextTransformable<T> getTransformer(Class<T> type) { 
     ... 
    } 

कोड सही ट्रांसफार्मर जरूरी सुंदर नहीं है, लेकिन कॉल करने परिप्रेक्ष्य सब कुछ से अच्छी तरह से प्रस्तुत किया जाता है खोजने के लिए।

संपादित करें 2: इस बारे में सोचकर, मैं क्या देख रहा हूं कि आप ऑब्जेक्ट निर्माण को नियंत्रित करना चाहते हैं। आप वास्तव में ऐसा नहीं कर सकते हैं।दूसरे शब्दों में, जावा में आप एक कार्यान्वयनकर्ता को अपनी वस्तु बनाने के लिए कारखाने का उपयोग करने या उपयोग करने के लिए मजबूर नहीं कर सकते हैं। वे हमेशा एक सार्वजनिक कन्स्ट्रक्टर का पर्दाफाश कर सकते हैं। मुझे लगता है कि आपकी समस्या यह है कि आप निर्माण को लागू करने के लिए तंत्र से खुश नहीं हैं। यदि वह समझ सही है, तो निम्न पैटर्न का उपयोग किया जा सकता है।

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

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

मुझे लगता है कि वे कहते हैं कि ऐसी कोई सॉफ़्टवेयर समस्या नहीं है जिसे संकेत की अतिरिक्त परत के माध्यम से हल नहीं किया जा सकता है, लेकिन यह एक पुल बहुत दूर हो सकता है। विचार के लिए कम से कम भोजन।

+0

के प्रभारी अपवाद हैंडलिंग रखता है हां, मैं नोट के साथ ऊपर संपादित करूँगा कि हमने फ्लाईवेट के बारे में बात की है - वास्तव में हालांकि मुझे लगता है कि हम ध्यान केंद्रित कर रहे हैं पहुंच की एकता (उदाहरण के लिए मार्कर इंटरफ़ेस की तरह, और सबक्लास पर अनुबंध लागू करना) - इनमें से कोई भी कारखाना या स्थैतिक ट्रांसफॉर्मर ऐसा महसूस नहीं करता है जैसे वे हमें प्राप्त करते हैं) मुख्य कारण मुझे लगता है कि हम कारखाने के विचार से खुश नहीं हैं हालांकि, कभी-कभी हम अनजान महसूस करते हैं, जब हम कुछ सुरुचिपूर्ण के साथ नहीं आ सकते हैं ... – jayshao

+0

हां, विडंबनात्मक रूप से प्रतिबंधित करना हम चाहते हैं;) आदर्श रूप से मिश्रण के अधिक, लेकिन सहयोगी का उपयोग किए बिना वस्तु - हालांकि मैं सहमत हूं, आपका सारांश हमारी वर्तमान सोच के समान है और संभवतः उतना ही अच्छा है जितना हम अभी तक आने में सक्षम होने जा रहे हैं। – jayshao

1

यदि आप जावा 5 या उच्चतर में चल रहे हैं, तो आप enum प्रकार का उपयोग कर सकते हैं - ये सभी परिभाषा, सिंगलेट्स द्वारा हैं।

public enum MyEnumType { 
    Type1, 
    Type2, 
    //.... 
    TypeN; 

    //you can do whatever you want down here 
    //including implementing interfaces that the enum conforms to. 

} 

इस तरह स्मृति समस्या दूर हो जाने, और आप कार्यान्वित व्यवहार के एक हो सकते हैं: तो तुम कुछ की तरह कर सकते थे।


संपादित करें: आप (पहले 1.4 या) enums के लिए उपयोग नहीं है, तो या, किसी अन्य कारण से, वे आप के लिए काम नहीं करते, मैं एक Flyweight pattern कार्यान्वयन की सिफारिश करेंगे।

+0

आप नीचे देख सकते हैं कि क्यों हम जावा 5+ – jayshao

+0

@jayshao में enum समर्थन में निर्मित क्षमताओं से परे जाने के लिए एक सम्मेलन के साथ आने का प्रयास कर रहे हैं, हमें मूल्य के साथ एक समान समस्या थी, और इसके आसपास काम किया। लेकिन मुझे लगता है कि एक सिंगलटन रजिस्ट्री के साथ एक फ्लाईवेट पैटर्न, आपके लिए उस मुद्दे के एक बड़े हिस्से के आसपास काम करेगा, जैसा कि @Yishai – aperkins

+0

@aperkins द्वारा किसी भी नमूना कोड द्वारा समझाया गया है? – jayshao

4

बस एक विचार पर विचार करना: आप वस्तुओं से परिवर्तन तर्क अलग कर सकते हैं खुद को, और फिर आप ट्रांसफॉर्मर के पास निर्धारित है, तो निम्न इंटरफ़ेस को लागू करने:

public interface Transformer<T>{ 

    public T fromText(String text); 

    public String toText(T obj); 
} 

आपका वास्तविक डेटा कक्षाएं एक हो सकता है विधि getTransformer() जो उनके लिए सही ट्रांसफॉर्मर देता है।

+1

मां स्लीपर! आपने मुझे इसमें हरा दिया!:) – les2

+0

हम कोड को सह-स्थित रखने की उम्मीद कर रहे हैं - ये मूल रूप से केवल मूल्य वस्तुएं हैं, इसलिए आदर्श रूप से यह – jayshao

0

जैसा कि @aperkins ने कहा, आपको enums का उपयोग करना चाहिए।

enum आधार वर्ग, Enum, एक valueOf विधि है कि एक उदाहरण के लिए एक स्ट्रिंग में परिवर्तित कर देंगे प्रदान करता है।

enum MyEnum { A, B, C; } 
// Here's your toText 
String strVal = MyEnum.A.getName(); 
// and here's your fromText 
MyEnum value = MyEnum.valueOf(MyEnum.class, strVal); 

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

/** Enums can implement this to provide a method for resolving a string 
    * to a proper enum name. 
    */ 
public interface EnumHelp 
{ 
    // Resolve s to a proper enum name that can be processed by Enum.valueOf 
    String resolve(String s); 
} 

/** EnumParser provides methods for resolving symbolic names to enum instances. 
    * If the enum in question implements EnumHelp, then the resolve method is 
    * called to resolve the token to a proper enum name before calling valueOf. 
    */ 
public class EnumParser 
{ 
    public static <T extends Enum<T>> T fromText(Class<T> cl, String s) { 
     if (EnumHelp.class.isAssignableFrom(cl)) { 
      try { 
       Method resolve = cl.getMethod("resolve", String.class); 
       s = (String) resolve.invoke(null, s); 
      } 
      catch (NoSuchMethodException ex) {} 
      catch (SecurityException ex) {} 
      catch(IllegalAccessException ex) {} 
      catch(IllegalArgumentException ex) {} 
      catch(InvocationTargetException ex) {} 
     } 
     return T.valueOf(cl, s); 
    } 

    public <T extends Enum<T>> String toText(T value) 
    { 
     return value.name(); 
    } 
} 
+0

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

+0

यदि आप valueOf() के व्यवहार को पसंद नहीं करते हैं तो कुछ भी आपको अपने enum पर एक कस्टम लुकअप विधि जोड़ने से रोकता है। यदि आप किसी लुकअप विधि की आवश्यकता होती है तो आप अक्सर ऐसा करेंगे जो शून्य या डिफ़ॉल्ट मान देता है यदि कुछ भी नहीं मिला। ValueOf() के साथ आप केवल कोशिश/पकड़ के साथ ऐसा कर सकते हैं जो नियंत्रण प्रवाह –

0

ऐसा लगता है कि आपको कारखाने को निर्मित वस्तु से अलग करने की आवश्यकता है।

public interface TextTransformer<T> { 
    public T fromText(String text); 
    public String toText(T source); 
} 

आप TextTransformer कक्षाएं रजिस्टर कर सकते हैं जैसे आप चाहें:

public class FooTextTransformer implements TextTransformer<Foo> { 
    public Foo fromText(String text) { return ...; } 
    public String toText(Foo source) { return ...; } 
} 

आप FooTextTransformer एक सिंगलटन होना चाहते हैं, तो आप वसंत कि लागू करने के लिए की तरह एक कंटेनर का उपयोग कर सकते हैं। गूगल अपने codebase से सभी मैन्युअल रूप से लागू एकमात्र दूर करने के लिए एक परियोजना शुरू की है, लेकिन अगर आप एक पुराने ढंग सिंगलटन क्या करना चाहते हैं, तो आप एक उपयोगिता वर्ग इस्तेमाल कर सकते हैं:

Foo foo = TextTransformers.FOO.fromText(...); 
... 
foo.setSomething(...); 
... 
String text = TextTransformers.FOO.toText(foo); 
:

public class TextTransformers { 
    public static final FooTextTransformer FOO = new FooTextTransformer(); 
    ... 
    public static final BarTextTransformer BAR = new BarTextTransformer(); 
} 

अपने ग्राहक कोड में

यह मेरे सिर के ऊपर से सिर्फ एक तरीका है।

2

एक पूरी तरह से अलग दृष्टिकोण (और उस मामले के लिए एक बदसूरत हैक) इंटरफ़ेस को एक विधि देता है जो एक विधि देता है।

public interface MyInterface{ 
    Method getConvertMethod(); 
} 

अब अपने ग्राहक कोड कर सकते हैं

yourInterface.getConvertMethod().invoke(objectToBeConverted); 

यह बहुत शक्तिशाली है, लेकिन बहुत बुरा एपीआई डिजाइन

शॉन

+0

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

+0

बिल्कुल, क्योंकि जावा में विधियां "प्रथम श्रेणी के नागरिक" नहीं हैं। हालांकि यह जल्द ही जेडीके 1.7 में बदल सकता है। हम देखेंगे कि प्रोग्रामिंग शैली में कितना बदलाव आया है ... –

1

बस एक अलग विचार। सभी मामलों के लिए लागू नहीं है, लेकिन शायद किसी और की मदद करें।

आप अपने interface और आपके concrete classes के बीच पुल के रूप में abstract class का उपयोग कर सकते हैं। सार वर्ग स्थिर तरीकों के साथ ही अनुबंध विधियों की परिभाषाओं की अनुमति देता है। उदाहरण के तौर पर, आप कलेक्शन एपीआई देख सकते हैं, जहां सूर्य ने सभी ठोस कक्षाओं से शून्य से कोडिंग बल के बजाय कई अमूर्त वर्गों को लागू किया।

कुछ मामलों में, आप केवल सार कक्षाओं द्वारा इंटरफेस को प्रतिस्थापित कर सकते हैं।

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