जावा में कई सामान्य इंटरफेस को लागू करना


10

मुझे एक इंटरफ़ेस की आवश्यकता है जो मुझे एक निश्चित विधि का आश्वासन देता है, जिसमें विशिष्ट हस्ताक्षर भी शामिल है, उपलब्ध है। अब तक उसका वही है जो मेरे पास है:

public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

समस्या तब उत्पन्न होती है जब एक वर्ग को कई अन्य संस्थाओं के लिए अनुपयुक्त होना चाहिए। आदर्श मामला यह होगा (जावा नहीं):

public class Something implements Mappable<A>, Mappable<B> {
    public A mapTo(A someObject) {...}
    public B mapTo(B someOtherObject) {...}
}

इस शेष को "सामान्य" के रूप में प्राप्त करने का सबसे अच्छा तरीका क्या होगा?

जवाबों:


10

यह निश्चित रूप से है, न कि कुछ ऐसा जो आप टाइप एरासुरे के कारण कर सकते हैं । रनटाइम पर, आपके पास दो विधियाँ हैं public Object mapTo(Object), जो स्पष्ट रूप से सह-अस्तित्व में नहीं आ सकती हैं।

दुर्भाग्य से, आप जो करने की कोशिश कर रहे हैं, वह केवल जावा के प्रकार प्रणाली से परे है।

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

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


3

जैसा कि आपने देखा, आप विभिन्न प्रकार के मापदंडों के साथ एक ही इंटरफ़ेस को दो बार लागू नहीं कर सकते हैं (मिटाए जाने के कारण: रनटाइम के दौरान वे एक ही इंटरफेस हैं)।

इसके अलावा, यह दृष्टिकोण एकल जिम्मेदारी सिद्धांत का उल्लंघन करता है: आपकी कक्षा को एक Something(जो भी मतलब हो) होने पर ध्यान केंद्रित करना चाहिए और उस कार्य के अलावाA या उसके लिए मैपिंग नहीं करना चाहिए ।B

ऐसा लगता है कि आपको वास्तव में ए Mapper<Something,A>और ए होना चाहिए Mapper<Something,B>। इस तरह प्रत्येक कक्षा में एक ही स्पष्ट रूप से परिभाषित जिम्मेदारी है और आप एक ही इंटरफ़ेस को दो बार लागू करने की समस्या में नहीं चलते हैं।


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

@ इस्टानी: हाँ, वे कुछ हद तक कपल हैं, लेकिन उनकी अलग ज़िम्मेदारियाँ हैं। इस बारे में भी सोचें: जब आप एक नई कक्षा शुरू Cकरते हैं और आप Somethingइसके लिए अनुपयुक्त होना चाहते हैं , तो आपको संशोधित करने की आवश्यकता होगी Something, जो बहुत अधिक युग्मन है। बस एक नया जोड़ने SoemthingToCMapperसे कम घुसपैठ है।
जोकिम सॉउर

1
+1 यह - आम तौर पर बोलना चाहिए कि यदि आप ओपी (जावा में) क्या चाहते हैं, तो आपको विरासत पर रचना का पक्ष लेना चाहिए। डिफ़ॉल्ट विधियों के साथ जावा 8 यह और भी आसान बनाता है - लेकिन हर कोई अभी तक रक्तस्राव के किनारे पर नहीं कूद सकता है :-)।
मार्टिनेज वर्बर्ग

0

यह देखते हुए कि गुणकों के इंटरफेस को लागू करने की अनुमति नहीं है, आप इनकैप्सुलेशन के उपयोग पर विचार कर सकते हैं। (उदाहरण java8 + का उपयोग करके)

// Mappable.java
public interface Mappable<M> {
    M mapTo(M mappableEntity);
}

// TwoMappables.java
public interface TwoMappables {
    default Mappable<A> mapableA() {
         return new MappableA();
    }

    default Mappable<B> mapableB() {
         return new MappableB();
    }

    class MappableA implements Mappable<A> {}
    class MappableB implements Mappable<B> {}
}

// Something.java
public class Something implements TwoMappables {
    // ... business logic ...
    mapableA().mapTo(A);
    mapableB().mapTo(B);
}

कृपया आगे की जानकारी और अधिक उदाहरणों के लिए यहां देखें: एक जावा वर्ग कैसे बनाया जाए जो एक इंटरफ़ेस को दो सामान्य प्रकारों के साथ लागू करता है?


-1
public interface IMappable<S, T> {
    T MapFrom(S source);
}

// T - target
// S - source

यदि आप UserDTO में उपयोगकर्ता को मैप करना चाहते हैं और UserViewModel को उपयोगकर्ता को मैप करना चाहते हैं, तो आपको दो अलग-अलग कार्यान्वयन की आवश्यकता होगी। एक ही वर्ग में इस सारे तर्क को ढेर मत करो - ऐसा करने का कोई मतलब नहीं है।

जोआचिम को खुश रखने के लिए अपडेट करें

public interface ITypeConverter<TSource, TDestination>
{
    TDestination Convert(TSource source);
}

लेकिन अब हम आटोमैपर दायरे ( http://automapper.codeplex.com/wikipage?title=Custom%20Type%20Converters ) में हैं


मुझे नहीं लगता IMappableकि किसी चीज के लिए एक अच्छा नाम है जो अन्य चीजों को मैप करता है। Mapper(या IMapper, यदि आप ;-)) शायद अधिक सही है। (वैसे: नहीं, यह मेरा अपमान नहीं था)।
जोकिम सॉउर

मैंने इस प्रश्न को लिया है और एक I के साथ उपसर्ग किया है कि यह एक इंटरफ़ेस है। मैं सवाल के अनुसार डिजाइन की समस्या को हल कर रहा हूं, नामकरण की समस्या के विपरीत।
कोडर्ट

1
क्षमा करें, लेकिन मेरी राय में एक वास्तव में एक डिजाइन समस्या को "हल" नहीं कर सकता है और नामकरण की उपेक्षा कर सकता है। डिजाइन का मतलब है समझने योग्य संरचनाएं। गलत नामकरण समझने की समस्या है।
जोकिम सॉउर

अपडेट को अपने दिमाग को आराम देना चाहिए ;-)
कोडार्ट

1
@ कोड अगर मैंने आपके उत्तर को सही ढंग से समझा तो इसका अर्थ है "मैपफ्रॉम" (जिसे कम किया जाना चाहिए; ;-) वस्तु बनाता है। मेरे मामले में यह पहले से ही बनाई गई वस्तु पर जानकारी भर रहा है।
एस्टानी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.