2014-02-09 90 views
2

我有一個基類作爲這樣一個不變的基礎:創建通用的方法

public abstract class BasePiece extends Serialisable { 
    public final Position[] shape; 
    public final Position position; 

    public abstract Position[] getInitialShape(); 

    public BasePiece() { 
     position = new Position(0, 0); 
     shape = getInitialShape(); 
    } 
    public BasePiece(Position pos, Position[] initialShape) { 
     position = pos; 
     shape = initialShape; 
    } 

    public BasePiece Moved(Position offset) { 
     return BasePiece(position.add(offset), shape); 
    } 

    public BasePiece Rotated() { 
     return BasePiece(position, shape.Rotated()); 
    } 
} 

不過,我想移動和旋轉回到它繼承這個類的類的實例。我對Java很陌生,並且有一些C#的經驗,我試圖做到以下幾點:

public <T extends BasePiece> T Moved(Position offset) { 
    return T(position.add(offset), shape); 
} 

public <T extends BasePiece> T Rotated() { 
    return T(position, shape.Rotated()); 
} 

有沒有什麼辦法做到這一點?我最初嘗試解決這個問題的方法是讓形狀和位置不再是最終的,並且使Moved和Rotate Move和Rotate方法改變這個狀態。我真的想使對象不可變,因爲它會使我的應用程序的其餘部分更易於管理。

+0

編輯說明:Serializable是一個接口。你的抽象基類需要實現它,而不是擴展它,所以你會得到該行的編譯錯誤。我懷疑你已經知道了,這只是一個錯字。 –

+0

另外,你正在調用一個方法'旋轉()'離開數組,但是一個數組沒有任何這樣的方法。編譯器會給你一個'symbol not found'錯誤。 –

+0

嘎對不起,我試圖簡化我的例子有點太多,我其實有一個類定義在這裏有一個旋轉的方法,你正確的實現/延伸 – theheadofabroom

回答

1

我認爲這與泛型很少有關。您可以留下您的方法聲明爲:

public BasePiece Moved(Position offset) { 
     return BasePiece(position.add(offset), shape); 
} 

,並繼承它的類:

class ExtendPiece extends BasePiece { 

    @Override 
    public BasePiece Moved(Position offset) { 
      return ExtendPiece(position.add(offset), shape); 
    } 

} 

ExtendPiece可以上下鑄造到BasePiece

但隨後的過程中,你將不得不自己投它:

ExtendPiece e = (ExtendPiece) obj.Moved(..); 

編輯:

只是一個快速的解決方法是使用所謂的雙重分派:

化妝每個子類實現方法newInstance(),它將在基類中抽象。在ExtendedPiece:

public BaseClass newInstance(Position pos, Position[] initialShape){ 
    return new ExtendedPiece(pos, initialShape); 
} 

和你的抽象方法的代碼:

public BasePiece Moved(Position offset) { 
    return this.newInstance(position.add(offset), shape); 
} 
+0

但這意味着我必須覆蓋每個子類,我有7個,只想要我的抽象方法被覆蓋 – theheadofabroom

+0

哦,對不起,我絕對沒有看到'T(position.add(偏移),形狀);'方法 –

+0

@theheadofabroom請參閱編輯,只是一個快速解決方法。 –

1

我假設你想在基類中只有一次定義泛型方法,並讓它們在自動工作你的子類。

是的,這可以用Java來完成。這比C#中的冗長一些,但這是你如何去做的。

首先,你必須把它添加到您的基類聲明:

public abstract class BasePiece<T extends BasePiece<T>> implements Serializable { 
    ... 
} 

然後,在你的方法,做到這一點(它涉及反射,你就必須導入的java.lang.reflect .Constructor):

public T Moved(Position offset) { 
     //Use reflection to invoke the constructor 
     @SuppressWarnings("unchecked") 
     Constructor<T> constructor = (Constructor<T>) this.getClass().getConstructor(Position.class, Position[].class); 
     T newInstanceOfSpecificType = null; 
     try { 
      // Cast result to T, which will be the subclass 
      newInstanceOfSpecificType = (T) constructor.newInstance(position.add(offset), shape); 
     } catch (Exception e) { 
      if (e instanceof NoSuchMethodException) { 
       throw new RuntimeException("You forgot to declare the appropriate constructor in " + this.getClass().getSimpleName() + "!\n"); 
      } 
      e.printStackTrace(); 
     } 
     return newInstanceOfSpecificType; 
    } 

的一個陷阱:你必須確保在所有的子類的簽名(位置,位置[])定義構造函數,你必須聲明你的子類具體如下:

public class ExtendedPiece extends BasePiece<ExtendedPiece> { 

    public ExtendedPiece(Posistion position, Position[] shape) { 
     return super(position, shape); 
    } 

}