[英]Have a class implement an unspecified generic interface in java
我有以下“通用”問題
這是我的通用消息界面。
public interface Message<P,R> {
void setParams(P Params); // and the corresponding getter
void setResults(R results);
}
為簡單起見,我想通過預定義參數和結果類型來指定消息的數量(接口)。 因此,如果您使用消息X,您就知道params和結果類型是什么。
如
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>
我想有一個通用的工廠方法,它將被賦予消息類,參數和結果對象,並將返回實現MyMessage接口的BaseMessage實例。 喜歡在下面
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中不可能出現的問題?
謝謝!
我擔心這樣的通用工廠是不可能的,因為你無法實例化類似的泛型類型
T a = new BaseMessage<T>();
您必須告訴編譯器確切的泛型類型參數。
您可以做的是創建每個具體消息類型的實例,並將它們存儲在地圖中,並將相應的類標記作為關鍵字。 然后工廠方法可以查找正確的消息並直接返回它,或者(如果需要單獨的實例)使用消息對象作為原型來創建要返回的實例。
在我們當前的項目中,我們有一些類似的設計,不同之處在於具體的子類是每個現有的類,具有不同的名稱和(不幸的是 - 但不是完全 - 重復的)實現。 所以我們可以使用標准類加載和Spring來實例化它們。
您尚未指定工廠如何決定使用哪個實現類,或者實現類是否需要任何自定義初始化邏輯或參數。 假設只使用默認構造函數實例化已注冊的實現類就足夠了,您可以這樣做:
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的並行類型層次結構嗎?
給定接口interface Message<P,R>
和interface MyMessage extends Message<String, String>
,類class BaseMessage<P,R> implements Message<P,R>
,這些是我看到的選項:
不要使用MyMessage
並使用Message<String, String>
替換所有實例。 你的工廠將是
public <P,R> Message<P, R> newMessage() { return new BaseMessage<P,R>(); }
有一節課
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; }
不要使用接口。
不要使用工廠。
(如果其他一切都破了)讓你的工廠成為
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。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.