簡體   English   中英

Java多態:如何避免類型轉換輸入參數?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM