2009-10-29 27 views
2

首先,我不知道標題是否反映了我的問題。如果你有更好的想法,我表示歉意,並請求改變。設計:在超類中的字段的子類中引用

現在,我遇到的問題主要是設計問題。我不確定我想要的是不錯的做法,但它很方便。

我有一個接口叫做IMovement

兩個類實現IMovementVelocityMovementSplineMovement

我也有一個類叫做雪碧。雪碧有一個IMovement

最後,我有兩個雪碧sublcasses:玩家敵人

知道球員總是VelocityMovement
知道敵人總是SplineMovement

除了超類參考IMovement之外,是否有錯誤(無論是通過設計還是實踐),都有分別來自Player或Enemy的VelocityMovement或SplineMovement屬性?

換句話說:

Interface IMovement { 
    public Vector2 getPosition(int time); 
} 

class VeloctiyMovement implements IMovement { 
    public Vector2 velocity; 

    public Vector2 getPosition(int time) { ... } 
} 

class SplineMovement implements IMovement { 
    public Spline spline; 

    public Vector2 getPosition(int time) { ... } 
} 

class Sprite { 
    IMovement movement; 
} 

class Player extends Sprite { 
    public VelocityMovement velocityMovement; 

    public Player() { 
    velocityMovement = new VelocityMovement(); 
    movement = velocityMovement; 
    } 
} 

class Enemy extends Sprite { 
    public SplineMovement splineMovement; 

    public Enemy() { 
    splineMovement = new SplineMovement(); 
    movement = splineMovement(); 
    } 
} 

我想在子類中的引用是方便的原因。有一半時間我需要玩家的速度場,另外一半時間我不在乎。這發生在一個遊戲中,該方法每秒被調用大約100次。

我指出100次的原因是因爲我也擔心鑄造是否昂貴。

實例代替,:

// When I need the velocity 
Vector2 velocity = ((VelocityMovement)player.movement).velocity; 
... 

// When I don't care 
Vector2 position = player.movement.GetPosition(time); 
... 

我現在可以這樣做:

Vector2 velocity = player.VelocityMovement.velocity; 
... 

Vector2 position = player.movement.GetPosition(time); 
... 

所以我的問題是:如果球員有VelocityMovement場和敵人有SplineMovement?或者這是一個糟糕的設計?

我想你的想法。

UPDATE

我現在還記得我爲什麼選擇具有的而不是雪碧實現IMovement(如JacobM正確建議)字段IMovement。

這是因爲在某些情況下,Enemy可能有SplineMovement和其他VelocityMovement。雖然我錯誤地說「我知道敵人總是會有SplineMovement」,但我應該說,我知道一個敵人在VelocityMovements收集所有敵人的地方有VelocityMovement。我希望你能理解我(否則我覺得自己像個白癡)。

例如:

List<Enemy> enemies = GetAllVelocityMovementEnemies(); 

我這樣做是因爲地方在我的遊戲邏輯,我想隻影響組具有VelocityMovements敵人。

所以,儘管JacobM的答案作爲設計是完全有效的,但這不適合我的情況。否則,我必須將Enemy與EnemyVelocityMovement和EnemySplineMovement等子類化,等等。

所以,很抱歉誤會,我決定Brian Agnew's答案是我設計的最佳答案。

哦,是的,關於鑄造的爭執實在是不成熟的優化。 ;)

+0

如果您根據語言對其進行標記,可能會有所幫助。 – Beta 2009-10-29 18:58:01

+0

雖然我主要關心這個設計,但是如果它有幫助的話,那就是C#(但也可能是Java) – pek 2009-10-29 19:04:48

回答

3

不要擔心目前的優化。不成熟的優化會讓你很悲傷,這很可能是不合理的。

因此,要回答您的問題,請不要在整個層次結構中重複字段 - 這是維護頭痛,您覺得節省的時間可以忽略不計。如果你按照DRY principle那麼你會爲自己節省很多頭痛。

問問你的類移動(比如說)通過類似:

player.move() 

否則(如你發現),你必須要找到自己的IMovement,然後抹上它,然後問了速度,這真的打破封裝。根據他們的具體情況,你的玩家/敵人級別可能會有不同的move()實現。

你可能不希望move()的方法,但我想要證明的是,情報是在類包含,而不是在調用代碼。所以你不應該公開你的IMovement對象。

最後,我只會在得到它之後進行優化,測量它以確定您有問題!

+0

我更新了我的問題。玩家/敵人確實有一個基類:雪碧。這確實包含了一種運動。 我的問題是最終,如果玩家/敵人還應該有一個VelocityMovement/SplineMovement,它們從Sprite繼承的IMovement除外。 – pek 2009-10-29 18:48:20

+0

剛剛看到的!更正 – 2009-10-29 18:48:54

+0

注意:VelocityMovement/SplineMovement在基類Sprite中具有SAME引用及其IMovement引用 – pek 2009-10-29 18:49:26

2

我沒有時間來嘗試編寫代碼,但也許,如果語言使用的是支持泛型類型,你可以不喜歡

class Sprite<T extends IMovement> { 
    T movement; 
} 

class Player extends Sprite<VelocityMovement> { 
} 

class Enemy extends Sprite<SplineMovement>{ 
} 

這樣,當你問玩家的運動對象,你已經知道它是一個VelocityMovement(但當然你也可以把它稱爲IMovement)。

+0

真棒的主意!從來沒有想到這一點! :P – pek 2009-10-29 19:03:20

+0

我仍然認爲真正的問題是封裝,並且對象應該自己看看它們的移動 – 2009-10-29 19:04:54

+0

我完全同意封裝問題。所以我會讓Sprite擴展IMovement,而VelocityMovement將會有setVelocity。 謝謝你們兩位。 ;) – pek 2009-10-29 19:10:03