2013-08-27 38 views
2

比方說,我有這兩個繼承層次:Java的並行繼承層次與泛型和協變返回

class EntityA { ... } 
class EntityB extends EntityA { ... } 

class EntityAPrime extends AbstractPrime<EntityA> { ... } 
class EntityBPrime extends EntityAPrime { ... } 

我也會喜歡協變返回類型:

public class EntityA { 
    public EntityAPrime prime() { 
    return new EntityAPrime(); 
    } 
} 

public class EntityB extends EntityA { 
    @Override 
    public EntityBPrime prime() { 
    return new EntityBPrime(); 
    } 
} 

到目前爲止好。

問題是我想EntityBPrime最終延伸AbstractPrime<EntityB>但由於它延伸EntityAPrime它最終延伸AbstractPrime<EntityA>

我可以讓EntityAPrimeEntityBPrime通用的,但後來我失去協變返回類型:

public class EntityA { 
    public EntityAPrime<EntityA> prime() { 
    return new EntityAPrime(); 
    } 
} 

public class EntityB extends EntityA { 
    @Override 
    public EntityBPrime<B> prime() { // ERROR: EntityBPrime extends EntityAPrime 
    return new EntityBPrime();  // but can't substitute <EntityB> for <EntityA> 
    } 
} 

一切正常,如果我回到一個綁定的通配符,但有一個與此有關disadvantages,我不會能夠調用AbstractPrime

我的另一個想法是使EntityAEntityB自己通用。

public class EntityA<T extends EntityA> { 
    public EntityAPrime<T> prime() { ... } 
} 

public class EntityB<T extends EntityB> extends EntityA<T> { 
    @Override 
    public EntityBPrime<T> prime() { ... } 
} 

這應該有效,但我認爲它會變得混亂(我們有超過100個實體會使用類似的模式)。

那麼,有沒有什麼辦法:

  • 保持協回報
  • 沒有使用上EntityAEntityB
  • 仿製藥沒有prime()返回一個綁定的通配符
  • ,並有EntityBPrime最終延長AbstractPrime<EntityB>代替AbstractPrime<EntityA>

注意:素數類是生成的代碼,但我可以控制生成的代碼。

+1

除非您打破A和B之間的繼承關係,您可以使用組合嗎? –

+0

@EricStein這些實體是在繼承的基礎上建模的,並以這種方式映射到表。雖然這真的很好。 –

+0

我想你就是在這條小溪上。擴展再次敲擊。 :-( –

回答

1

首先,您的接口和類都稱爲AB有點讓人困惑。所以,我已將這些課程分別更名爲AImplBImpl。此外,您的課程APrimeBPrime沒有輸入(他們需要),所以我認爲他們分別輸入<T extends A><T extends B>(如果我誤解了您的意圖/目標/要求,我很抱歉)。

private interface A {} 
private interface B extends A {} 
private abstract class AbstractPrime<T extends A>{} 
private class APrime<T extends A> extends AbstractPrime<T>{} 
private class BPrime<T extends B> extends APrime<T>{} 
private class AImpl {...} 
private class BImpl {...} 

我的第一個直覺是,如你所考慮的,在接口上鍵入實現。這會工作:

private class AImpl<T extends A> { 
    public APrime<T> prime(){ 
    return new APrime<>(); 
    } 
} 

private class BImpl<T extends B> extends AImpl<T> { 
    public BPrime<T> prime(){ 
    return new BPrime<>(); 
    } 
} 

但是,如果您已經在<T extends A>BPrime<T extends B>類型APrime,你需要的prime()返回類型打字?下面的解決方案可能適合你嗎?

class APrime<T extends A> extends AbstractPrime<T>{} 
class BPrime<T extends B> extends APrime<T>{} 

public class AImpl { 
    public APrime prime(){ 
    return new APrime<>(); 
    } 
} 

public class BImpl extends AImpl { 
    public BPrime prime(){ 
    return new BPrime<>(); 
    } 
} 

我想這個問題的答案是有點你是否設想需要如下:

private interface C extends B {} 

public void main(String[] args) { 
    BPrime<C> prime = new BImpl<C>().prime(); // do you need this? 
    BPrime<B> prime = new BImpl<>().prime(); // do you need this? 


    BPrime prime = new BImpl().prime(); or is this sufficient...? 
} 
+0

首先,感謝您抽出寶貴時間來幫忙。 ,我澄清了一些問題,沒有接口,我想避免'AImpl '其中'AImpl'是一個實體(請參閱問題稍微更詳細),雖然我們可能會同意使實體的一般聲音就像修復它的方法一樣,我也想避免使用原始類型,最後,回答「你需要這個嗎?」的問題,我不需要第一個,但是需要第二個問題。不能沒有'AImpl'通用。 –

1

正如我在註釋中提到,有很多這種類型的PARAMS地方都省略了,這讓整個故事看起來不正確。

首先,你的素數至少應該是這樣的:

class EntityAPrime<T extends EntityA> extends AbstractPrime<T> {} 

class EntityBPrime<T extends EntityB> extends EntityAPrime<T> {} 

接下來的問題涉及到你的實體

class EntityA { 
    public EntityAPrime<????> prime(); <- What should be the reasonable type param here? 
} 

class EntityB extends EntityA { 
    public EntityBPrime<????> prime(); <- Same here 
} 

答案取決於你的設計。

我不明白你的第二個選擇是多麼的混亂比你原來的一個(給原來的是真實的雜亂)

您可以考慮此(未測試,以及它是否是正確很大程度上取決於你的設計,但至少類型PARAMS看起來合理的我):

public class Entity<T> { 
    public Prime<T> prime(); 
} 

public class AbstractEntityA<T extends EntityA> extends Entity<T> { 
    @Override 
    public AbstractAPrime<T> prime(); 
} 

public class EntityA extends AbstractEntityA<EntityA>{ 
    public EntityAPrime prime() { ... } 
} 

public class EntityB extends AbstractEntityA<EntityB> { 
    public EntityBPrime prime() {...} 
} 


public class AbstractAPrime<T extends EntityA> extends AbstractPrime<T> {} 

public class EntityAPrime extends AbstractAPrime<EntityA>{} 
public class EntityBPrime extends AbstractAPrime<EntityB>{} 

簡言之,在原始EntityA內容移動到一個抽象類,爲此,由EntityA(大多隻是一個普通的擴展),並可以擴展EntityB(覆蓋並添加更多的東西)。 Prime同樣適用。

+0

我現在修正的問題中有一個錯誤。感謝您的注意,並花時間回答。 +1。讓實體泛化似乎可以解決問題,但是在我提到的問題中,它會很混亂。我們有100多個實體,我認爲他們都必須變得通用。此外,Hibernate不會返回通用實體,我不確定Spring Data會做什麼。雖然輸入這個,但我意識到只有繼承層次結構中的實體必須是通用的,我們沒有太多。 –