2015-06-11 9 views
5

मैं एक प्रकार-सुरक्षित कोड लिखना चाहता हूं। यहाँ मैं क्या करने की कोशिश की है या नहीं:एक प्रकार को सुरक्षित तरीके से लिखना

public interface ResultTronsformer<T>{ 
    public T tranform(T t); 
} 

public class BigDecimalTransformer implements ResultTRansformer<BigDecimal>{ 

    public BigDecimal transform(BigDecimal t){ 
     return t.setScale(0); 
    } 
} 

अब मैं कॉलम इंटरफ़ेस जो की तरह

public interface Column{ 
    public ResultTransformer<?> getTransformer(); 
} 

लग रहा है परिभाषित करने और विधि

public class Report{ 
    private Map<Column, Object> columnValuePairs; 

    public void putIntoACollection(Column c, Object columnsValue){ 
     ResultTransformer<?> rt = c.getTransformer(); 
     columnValuePairs.put(c, rt.transform(o)); //Error: Couldn't convert Object 
                //to the capture of wildcard 
    } 
} 

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

+1

जावा का प्रकार सिस्टम मजबूत enoug नहीं है यह करने के लिए एच। लेकिन आप कुछ रैपर पुस्तकालयों का उपयोग कर सकते हैं जो ** ** बाहरी ** सुरक्षित एपीआई का पर्दाफाश करते हैं। उदाहरण के लिए: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ClassToInstanceMap.html – Max

+0

@ मैक्स इंटरस्टिंग, उस दृष्टिकोण के बारे में नहीं सुना है। शायद आप एक उदाहरण के रूप में एक उदाहरण प्रदान कर सकते हैं? – user3663882

उत्तर

1

आप Column वर्ग बदल सकते हैं और कर सकते हैं यह parametrized:

public interface Column<T> { 
    public ResultTransformer<T> getTransformer(); 
} 

तो फिर तुम putIntoACollection विधि (Report parametrize करने की कोई जरूरत) parametrize करने के लिए है:

public class Report { 
    private Map<Column, Object> columnValuePairs; 

    public <T> void putIntoACollection(Column<T> c, T columnsValue) { 
     final ResultTransformer<T> rt = c.getTransformer(); 
     columnValuePairs.put(c, rt.transform(columnsValue)); 
    } 
} 

इस तरह, आप कभी नहीं कैप्चर प्रकार का उपयोग करने की आवश्यकता है।

यहाँ कैसे आप इसका इस्तेमाल होता है की एक उदाहरण है:

private class BigDecimalColumn implements Column<BigDecimal> { 
    @Override 
    public ResultTransformer<BigDecimal> getTransformer() { 
     return new BigDecimalTransformer(); 
    } 
} 

public static void main(String[] args) { 
    final Report report = new Report(); 
    report.putIntoACollection(new BigDecimalColumn(), new BigDecimal("3.14")); 
} 
+0

लेकिन आपको लगता है कि मैं कॉलम इंटरफ़ेस को तब कार्यान्वित कर सकता हूं? उदाहरण के लिए, मुझे 'BigDecimalColumn' की आवश्यकता है जो बदले में 'परिणाम ट्रान्सफ़ॉर्मर ' का एक उपन्यास है। हम एक कंपाइलर अनचेक चेतावनी प्राप्त करेंगे। – user3663882

+0

आप सही हैं। मैंने अपना जवाब अपडेट किया। –

+0

@ user3663882 यह प्रश्न इस तरह से हल करने के लिए असंभव होगा कि उस चेतावनी का उत्पादन नहीं करता है।करने के लिए एकमात्र चीज साबित रूप से सुरक्षित कोड लिखना होगा और '@SuppressWarning ("अनचेक") जोड़ें। – Max

1

जब आप ट्रांसफार्मर मिलता है, आप के प्रकार का उल्लेख करने की जरूरत है क्योंकि संकलक उस समय यह पता नहीं चलेगा।

कॉलम के getTransformer के लिए कक्षा को पैरामीटर के रूप में जोड़ने और एक विशेष परिणाम ट्रान्सफ़ॉर्मर को वापस करने का एक संभावित समाधान है।

public interface ResultTransformer<T> { 
    public T transform(T t); 
} 

public interface Column{ 
    public <T> ResultTransformer<T> getTransformer(Class<T> theClass); 
} 

public class Report{ 
    private Map<Column, Object> columnValuePairs; 

    public void putIntoACollection(Column c, Object o){ 
     ResultTransformer<Object> rt = c.getTransformer(Object.class); 
     columnValuePairs.put(c, rt.transform(o)); 
    } 

public interface ResultTransformer<T> { 
    public T transform(T t); 
} 

इंटरफ़ेस कॉलम को सामान्यीकृत करने का एक और तरीका होगा।

+0

फिर, कॉलम इंटरफ़ेस का कार्यान्वयन असुरक्षित होगा। या मैं कुछ समझ नहीं आता ....? – user3663882

+0

आप कॉलम इंटरफ़ेस को कॉलम पर सामान्यीकृत भी कर सकते हैं लेकिन यह परिणाम ट्रांस्फ़ॉर्मर के परिणामस्वरूप कॉलम के प्रकार पैरामीटर को बाध्य करेगा जो एक निर्भरता नहीं है जिसे मैं चुनूंगा। भविष्य में आप एक कॉलम के लिए एकाधिक ट्रांसफार्मर रखना चाहते हैं और यह अब और संभव नहीं होगा। यह इस बात पर निर्भर करता है कि किस वर्ग में ट्रांसफॉर्मर के रिटर्न प्रकार को परिभाषित करने की ज़िम्मेदारी होगी। यदि यह कॉलम है, तो कॉलम बनाएं। यदि यह परिणाम ट्रान्सफॉर्मर है तो यह एक अच्छा तरीका है। – Maarten

2

आप कॉलम के बारे में सोच सकते हैं जैसे कि यह किसी प्रकार का कंटेनर है जो विशिष्ट प्रकार रखता है। इस तरह, आप कॉलम घोषणा में सामान्य प्रकार का परिचय दे सकते हैं।

public interface Column<T>{ 
    public ResultTransformer<T> getTransformer(); 
} 

उसके बाद, आप रिपोर्ट विधि इस प्रकार बदल सकते हैं:

public <T> void putIntoACollection(Column<T> c, T columnsValue){ 
     ResultTransformer<T> rt = c.getTransformer(); 
     columnValuePairs.put(c, rt.transform(columnsValue)); 
} 
+0

स्टैक ओवरफ्लो में आपका स्वागत है - यह एक महान पहली पोस्ट है! सटीक। – Bohemian

+0

यह समस्या का समाधान नहीं करता है क्योंकि आप केवल एक प्रकार के कॉलम डाल सकते हैं। समस्या का मांस कॉलम विभिन्न प्रकारों को स्टोर करता है। – Max

+0

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

0

हम सभी दावों सिर्फ भगवान शापित कच्चे प्रकार का उपयोग

 ResultTransformer rt = c.getTransformer(); 

एक और अधिक मिथ्याभिमानी समाधान दे सकते हैं, -

static <T> T transform (ResultTransformer<T> rt, Object obj) 
    { 
     T t = (T)obj; // unchecked cast 
     return rt.transform(t); 
    } 


public void putIntoACollection(Column c, Object obj){ 
    ResultTransformer<?> rt = c.getTransformer(); 
    columnValuePairs.put(c, transform(rt, obj)); 

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