2017-09-07 20 views
6

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

public class HostExtractorFactory { 

private HostExtractorFactory() { 
} 

public static HostExtractor getHostExtractor(URL url) 
     throws URLNotSupportedException { 
    String host = url.getHost(); 

    switch (host) { 
    case HostExtractorABC.HOST_NAME: 
     return HostExtractorAbc.getInstance(); 
    case HostExtractorDEF.HOST_NAME: 
     return HostExtractorDef.getInstance(); 
    case HostExtractorGHI.HOST_NAME: 
     return HostExtractorGhi.getInstance(); 
    default: 
     throw new URLNotSupportedException(
       "The url provided does not have a corresponding HostExtractor: [" 
         + host + "]"); 
    } 
} 

}

समस्या उन अधिक यूआरएल अनुरोध कर रहे हैं पार्स किया जा सकता है, मेरे स्विच बयान से बढ़ रहा है जिसका मतलब है कि है। प्रत्येक बार जब कोई पार्सर के साथ आता है, तो मुझे इसे शामिल करने के लिए अपने कोड को संशोधित करना होगा।

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

public class HostExtractorFactory { 

private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>(); 

private HostExtractorFactory() { 
} 

public static HostExtractor getHostExtractor(URL url) 
     throws URLNotSupportedException { 
    String host = url.getHost(); 

    if(EXTRACTOR_MAPPING.containsKey(host)) { 
     return EXTRACTOR_MAPPING.get(host); 
    } else { 
     throw new URLNotSupportedException(
       "The url provided does not have a corresponding HostExtractor: [" 
         + host + "]"); 
    } 
} 

public static void register(String hostname, HostExtractor extractor) { 
    if(StringUtils.isBlank(hostname) == false && extractor != null) { 
     EXTRACTOR_MAPPING.put(hostname, extractor); 
    } 
} 

}

और उपयोगकर्ता इसे उस तरह से प्रयोग करेंगे:

public class HostExtractorABC extends HostExtractor { 

public final static String HOST_NAME = "www.abc.com"; 

private static class HostPageExtractorLoader { 
    private static final HostExtractorABC INSTANCE = new HostExtractorABC(); 
} 

private HostExtractorABC() { 
    if (HostPageExtractorLoader.INSTANCE != null) { 
     throw new IllegalStateException("Already instantiated"); 
    } 

    HostExtractorFactory.register(HOST_NAME, this); 
} 

public static HostExtractorABC getInstance() { 
    return HostPageExtractorLoader.INSTANCE; 
} 
... 

}

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

एस

+1

आप ** प्रतिबिंब ** का उपयोग कर सकते हैं या आपको कहीं भी ज्ञात या "उपलब्ध होना चाहता था" वर्गों को सूचीबद्ध करना होगा, उदा। एक विन्यास फाइल ... उदा। 'org.reflections' वर्ग पथ स्कैन करने के लिए एक अच्छा हल्के lib है। – dedek

+1

कक्षा के नामों को एक साधारण पाठ फ़ाइल में सूचीबद्ध करें जो वे स्वयं को बनाए रख सकते हैं, फ़ैक्टरी निर्माण को एक स्थिर कंस्ट्रक्टर में ले जाएं और सभी प्रविष्टियों पर 'class.forname' (https://stackoverflow.com/q/8100376/13075) का उपयोग करें एक फैक्टरी प्रारंभिक विधि में फ़ाइल का। – Henrik

+1

वैकल्पिक रूप से: एक एनोटेशन पेश करें जो वे अपनी कक्षाओं पर लागू होते हैं, और कारखाने में उस के लिए कक्षा के पथ को स्कैन करते हैं। – Henrik

उत्तर

1

मैं तुम्हें के बारे में निर्भरता इंजेक्शन (मैं वसंत प्यार कार्यान्वयन) जानने के लिए सलाह होगा। इसके बाद आप की तरह

public interface HostExtractorHandler { 
    public String getName(); 
    public HostExtractor getInstance(); 
} 

एक इंटरफेस लिखने में सक्षम से अपने कोड सभी वर्गों है कि इस इंटरफेस को लागू करता है के लिए "पूछना" कर सकते हैं, तो आप अपने वर्ग के प्रारंभ चरण में अपने नक्शे का निर्माण करने में सक्षम हो जाएगा हो जाएगा।

+0

क्या आप शायद कुछ उदाहरण कोड जोड़ सकते हैं, वसंत में इस इंटरफ़ेस को लागू करने वाले सभी वर्गों के लिए * "पूछें" कैसे करें ...? – dedek

+2

यहां एक अच्छा उदाहरण है: https://dzone.com/articles/load-all-implementors –

2

एक और विकल्प Service Loader दृष्टिकोण का उपयोग करना है।

अपने इसको लागू करने के बाद ./resources/META-INF/services/your.package.HostExtractor में निम्नलिखित की तरह कुछ जोड़ें:

HostExtractorFactory() { 
    final ServiceLoader<HostExtractor> loader 
      = ServiceLoader.load(your.package.HostExtractor.class); 

    for (final HostExtractor registeredExtractor : loader) { 
     // TODO - Perform pre-processing which is required. 
     // Add to Map? Extract some information and store? Etc. 
    } 
} 
+0

वाउ, यह नहीं पता था कि ऐसी चीज सादे जावा में उपलब्ध है! – dedek

+0

यदि आप यह पूछकर गठबंधन करते हैं कि कुछ होस्ट एक्स्ट्रेक्टर 'होस्ट' से संबंधित हैं या तो इंटरफ़ेस विधि हो या केवल 'होस्ट' को नाम भाग में बदलकर, केवल आपके ऐप को केवल एक एसपीआई इंटरफ़ेस पता होना चाहिए। –

+0

लेकिन आपको 'मेटा-आईएनएफ/सेवाओं/your.package.HostExtractor' फ़ाइल में सभी वर्गों को सूचीबद्ध करना होगा ... – dedek

1

मैं Reflections library का प्रयोग करेंगे पारसर्स पता लगाने के लिए:

their.package1.HostExtractorABC 
their.package2.HostExtractorDEF 
their.package3.HostExtractorGHI 
... 

फिर अपने कोड में, आप की तरह कुछ हो सकता है।

Reflections reflections = new Reflections("base.package");  
Set<Class<? extends HostExtractor>> extractorTypes = 
    reflections.getSubTypesOf(HostExtractor.class); 

अपने कारखाने में उदाहरण बना करने के लिए परिणामों का उपयोग करें:

for (Class<? extends HostExtractor> c : extractorTypes) { 
    HostExtractor he = c.newInstance(); 
    EXTRACTOR_MAPPING.put(he.getHostName(), he); 
} 

मैं getHostName विधि बना वे सब HostExtractor वर्ग से निकाले जाते हैं, इसलिए सभी उप-प्रकारों का पता लगाने की लाइब्रेरी का उपयोग करने के लिए प्रकट , लेकिन HostExtractor बेस क्लास में जोड़ने के लिए यह छोटा होना चाहिए।

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