[英]Java Polymorphism : How can I avoid type casting input parameters?
假設我們有一個帶compare()函數的Parent接口。
public interface Parent {
public int compare(Parent otherParent);
}
假設子項Child1,Child2,Child3實現此接口Parent
public class Child1 implements Parent {
@Override
public int compare(Parent other) {
Child1 otherChild = (Child1)other;
}
}
另外,我在代碼中的其他地方使用泛型<T extends Parent>
。 所以我需要從代碼的其他部分比較兩個類型為T的對象。
我理解這是一個糟糕的設計,因為我在compare()函數中類型化了Parent對象,我甚至不知道輸入是否是Child1類型。
在使用泛型時如何避免這種類型的轉換?
為什么不呢?
interface Parent<T extends Parent<?>> {
int compare(T type);
}
class Child1 implements Parent<Child1>{
@Override
public int compare(Child1 type) {
return 0;
}
}
編輯:為確保正確使用,您可以使用
interface Parent<T extends Parent<T>>{ /* ... */ } //instead of wildcard
但說實話,“循環”看起來並不漂亮,而且由於Java中的Generics在RunTime上不起作用( 更多信息 ),它們基本上是語法糖,因為你稱之為“糟糕設計”的同一個演員,所以我不喜歡我認為你目前的做法很糟糕。
答案取決於您如何處理繼承層次結構:
instanceof
保護它 以下是使用抽象類的示例實現:
// Use this class as the base class of your Child classes
class AbstractChild implements Parent {
@Override
public int compare(Parent otherObj) {
if (!()) {
throw new IllegalStateException("Unexpected implementation of Child");
}
AbstractChild other = (AbstractChild)otherObj;
return doCompare(other);
}
protected abstract int doCompare(AbstractChild other);
protected abstract int accept(Child1 c1);
protected abstract int accept(Child2 c2);
protected abstract int accept(Child3 c3);
}
class Child1 extends AbstractChild {
@Override
protected int doCompare(AbstractChild other) {
return other.accept(this);
}
@Override
protected int accept(Child1 c1) {
// Compare c1 instance to this object
}
@Override
protected int accept(Child2 c2) {
// Compare c2 instance to this object
}
@Override
protected int accept(Child3 c3) {
// Compare c3 instance to this object
}
}
class Child2 extends AbstractChild {
@Override
protected int doCompare(AbstractChild other) {
return other.accept(this);
}
@Override
protected int accept(Child1 c1) {
// Compare c1 instance to this object
}
@Override
protected int accept(Child2 c2) {
// Compare c2 instance to this object
}
@Override
protected int accept(Child3 c3) {
// Compare c3 instance to this object
}
}
class Child3 extends AbstractChild {
@Override
protected int doCompare(AbstractChild other) {
return other.accept(this);
}
@Override
protected int accept(Child1 c1) {
// Compare c1 instance to this object
}
@Override
protected int accept(Child2 c2) {
// Compare c2 instance to this object
}
@Override
protected int accept(Child3 c3) {
// Compare c3 instance to this object
}
}
這種方法中唯一的演員是抽象類級別。 實際比較邏輯的實現包含在accept
方法中,其中比較在兩個已知類型的對象之間進行。
你不能。 Java接口正如其名稱所暗示的那樣 - 一個界面決定了接受的類型; 因此,在接口中定義的編譯時需要具有完全相同的方法簽名。
是的,將它轉換回Child類型感覺就像糟糕的設計 - 但它確實是Java規定的糟糕設計,所以這不是你的錯。
在一般情況下你無法避免它。 但是,如果修改了子類的數量,則可以應用類似於訪問者模式的內容,以避免在編寫更多代碼時進行轉換:
interface Parent {
int compare(Parent p);
protected int compareWith(Child1 c);
protected int compareWith(Child2 c);
protected int compareWith(Child3 c);
}
class Child1 implements Parent {
@Override int compare(Parent p) {
return p.compareWith(this);
}
@Override int compareWith(Child1 c) {
//specific code to child1
}
@Override int compareWith(Child2 c) {
//specific code to child2
}
@Override int compareWith(Child3 c) {
//specific code to child3
}
}
// and so on for the other children
這確實避免了施法,但我不確定在你在這里展示的情況下額外的努力是值得的。
你在那里描述的模式恰好是Comparable
的模式。 實際上,您應該考慮省略您的Parent
接口,而是將其替換為Comparable
。
Comparable
接口及其用法也顯示了如何解決這個問題:類型可以作為參數給出,以確保只有匹配類型可以傳遞給compare
方法:
interface Parent<T> {
int compare(T that);
}
class Child1 implements Parent<Child1> {
@Override
public int compare(Child1 that) {
...
}
}
對於所有其他情況,您至少必須考慮當不同的Child
-classes相互比較時會發生什么:
Child1 c1 = new Child1();
Child2 c2 = new Child2();
// Should this be possible? What should happen here?
// How should different child classes be compared?
c1.compare(c2);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.