2010-09-29 40 views
1

我有以下「通用」問題有一個類實現java中未指定的通用接口

這是我的通用消息接口。

public interface Message<P,R> { 
    void setParams(P Params); // and the corresponding getter 
    void setResults(R results); 
} 

爲了簡單起見,我想通過預定義參數和結果類型來指定消息的數量(接口)。所以,如果你使用消息X,你知道參數和結果類型是什麼。

public interface MyMessage extends Message<String,String> {} 

這工作正常,現在我想有一個共同的基類,它可以實現任何消息。

public class BaseMessage<P,R> implements Message<P,R> { 
    P param; 
    R results; 
    // base implementation 
} 

現在上面的問題是我不能有一個實現MyMessage的BaseMessage。

public class BaseMessage<T extends BaseMessage<P,R>> implements Message<P,R> 

public class BaseMessage<? extends BaseMessage<P,R>> implements Message<P,R> 

多次嘗試將無法正常工作,因爲編譯器抱怨P和R未綁定。 將它們作爲附加參數引入時會再次起作用,但此時所得到的類將不能被轉換爲BaseMessage或所需的MyMessage。

public class BaseMessage<P,R,T extends BaseMessage<P,R>> implements Message<P,R> 

我想有一個通用工廠方法,該方法將被給予所述消息類,參數和結果對象並且將返回BaseMessage的一個實例,其實現了MyMessage接口。像在以下內容

public static <P, R, T extends Message<P,R>> T factory(Class<T> clazz,P p,R r) { 
    T a = (T) new BaseMessage<P,R>(); 
    // create a BaseMessage which which Implements T 
    a.setParams(p); 
    a.setResults(r); 
    return a; 
} 

任何人都遇到過類似的問題,或者是在Java中不可能的東西?

謝謝!

+0

'公共接口MyMessage擴展BaseMessage'這是行不通的,在你的例子中BaseMessage是一個類。 – Cephalopod 2010-09-29 10:13:56

+0

感謝您的評論,它應該確實讀取 公共接口MyMessage擴展消息<字符串,字符串> {} – Joey 2010-09-29 10:33:53

回答

0

鑑於接口interface Message<P,R>interface MyMessage extends Message<String, String>和類class BaseMessage<P,R> implements Message<P,R>,這些都是我看到的選項:

  1. 不要使用MyMessageMessage<String, String>替換所有實例。你的工廠將是

    public <P,R> Message<P, R> newMessage() { 
        return new BaseMessage<P,R>(); 
    } 
    
  2. 有一個類

    class MyBaseMessage extends BaseMessage<String, String> implemens MyMessage 
    

    本廠將以

    public <M extends Message> M newMessage(Class<M> m) { 
        if (m.isAssignableFrom(MyBaseMessage.class)) { 
         return (M) new MyBaseMessage(); 
        } 
        if (m.isAssignableFrom(BaseMessage.class)) { 
         return (M) new BaseMessage(); 
        } 
        return null; 
    } 
    
  3. 不要使用接口。

  4. 請勿使用工廠。

  5. (如果一切休息時間)讓你的工廠是

    public <M extends Message> M newMessage(Class<M> m) { 
        try { 
         return getImplClass(m).newInstance(); 
        } catch (Exception ex) { /* do proper error handling */ } 
    } 
    

    getImplClass():使用了Javassist在運行時創建一個實現類實現接口的M和擴展BaseMessage。

3

恐怕這樣一個普通的工廠是不可能的,因爲你不能實例化泛型類型,如

T a = new BaseMessage<T>(); 

你必須告訴編譯器確切的泛型類型參數。

可以創建每個具體消息類型的實例,並將它們存儲在具有相應類標記作爲關鍵字的映射中。然後,工廠方法可以查找正確的消息並直接返回它,或者(如果您需要單獨的實例)使用消息對象作爲prototype來創建要返回的實例。

我們已經在我們目前的項目有些類似的設計,不同之處在於具體的每個子類都存在的類,具有鮮明的名稱和(不幸的是大部分 - 但不完全 - 重複)執行。所以我們可以使用標準的類加載和Spring來實例化它們。

1

您尚未指定工廠如何決定使用哪個實現類,或者實現類是否需要任何自定義初始化邏輯或參數。假設簡單地使用默認的構造函數是足夠的實例註冊實現類,你可以這樣做:

interface Message<P, R> { 
    void setParams(P Params); // and the corresponding getter 

    void setResults(R results); 
} 

interface StringMessage extends Message<String, String> { 
} 

abstract class MessageImpl<P, R> implements Message<P, R> { 
    P param; 
    R results; 
} 

abstract class StringMessageImpl extends MessageImpl<String, String> implements 
     StringMessage { 

} 
class ImplementationMap { 
    private Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>(); 

    public <T> void register(Class<T> interfaceClass, Class<? extends T> implementationClass) { 
     map.put(interfaceClass, implementationClass); 
    } 

    public <T> Class<? extends T> get(Class<T> interfaceClass) { 
     return map.get(interfaceClass).asSubclass(interfaceClass); 
    } 
} 

public class Test { 
    static final ImplementationMap messageImplementors = new ImplementationMap() {{ 
     register(StringMessage.class, StringMessageImpl.class); 
    }}; 

    static <P, R, M extends Message<P, R>> M create(Class<M> clazz, P p, R r) 
      throws Exception { 
     M m = messageImplementors.get(clazz).newInstance(); 
     m.setParams(p); 
     m.setResults(r); 
     return m; 
    } 

    public static void main(String[] args) throws Exception { 
     StringMessage m = create(StringMessageImpl.class, "p", "r"); 
    } 
} 

PS:你確定你是不是過度設計? DTO真的需要一個並行類型層次結構嗎?

+0

+1提及過度工程 – 2010-09-29 10:30:25

+0

我猜'M m = clazz.newInstance();'不會工作,因爲M是假設成爲一個界面。 – Cephalopod 2010-09-29 10:38:23

+0

是嗎? (OP寫入「將給予消息_class_」) – meriton 2010-09-29 10:41:33

相關問題