2015-10-18 132 views
0

好的,所以我有整個模塊負責在我的遊戲中生成玩家類,經過幾個小時和幾個小時的艱苦勞動,我想出了這個層次結構(代碼片段沒有使它太過圖形化,但仍然提供足夠的餘地)這是建立類層次結構的正確方法嗎?

我有實體(其或者是Player或怪獸)鹼接口:

public interface Entity { 
public int getHP(); 
... 
// all getters that denote all stats the Entities have in my game, nothing 
else is in the interface 
} 

然後是第二界面延伸Entity,稱爲Classes,包含所有相關類制定者:

public interface Classes extends Entity { 
void setHP(int a); 
... //and so on} 

最後有一些真正的階級,階層PlayerClasses負責建設類:

public class PlayerClasses implements Classes {  
private int HP, ATK, DEF, DAMAGE, DROP; 

@Override 
public int getHP() { 
    return HP; 
} 

@Override 
public void setHP(int a) { 
    HP = a; 
} 

// this is how I build the player class 
public void Rogue(){ 
    setHP(150); 
    setATK(30); 
    setDEF(20); 
    setDAMAGE(); 
} 

最後一類的構造函數用於創建播放器實例,然後將其傳遞到其他模塊(沒有繼承或直接訪問的任何其他類別字段或需要在構造函數中的任何狀態,所以贏吧?)

public class Player { 
private int HP,ATK,DEF,DAMAGE,DROP; 
private PlayerClasses c; 

public Player() { 
    c = new PlayerClasses(); 
    c.Rogue(); 
    HP = c.getHP(); 
    ATK = c.getATK(); 
    DEF = c.getDEF(); 
    DAMAGE = c.getDAMAGE(); 
    DROP = c.getDrop(); 
} 

類長的問題,但我試圖保持它的公民。任何反饋非常感謝。

編輯:好的,以澄清爲什麼我選擇這樣設計,我希望播放器實例是不可變的對象,只能使用正確的值實例化,同時保持其他模塊中的初始化儘可能沒有任何依賴關係。例如,如果模塊中的實例顯示玩家屬性和怪物屬性,則來自兩個不同玩家類的值不能混淆。我覺得在繼承中傳遞私有的HP和ATK變量,然後使用相同的變量拉動命名空間不是一種方法。

+0

有沒有*正確*的方式,但這不是一個*好*方式,恕我直言。爲什麼不用你的'Entity'接口,然後像'Player implements Entity'這樣的類?如果你有一些共享共同價值的類,可以引入類似「玩家延伸生物」,「怪物延伸生物」,「生物實現實體」等。 –

+0

這個問題太廣泛了。除非你澄清你爲什麼決定創建上述層次結構,以及你需要什麼建議,否則你的問題可能得不到有效答案 –

+0

在課堂設計中沒有「錯誤」,但有「這看起來很奇怪」。你需要那麼多的接口,然後委託給隱藏的類嗎?你可以創建具有不同默認值的'Player'的子類 – zapl

回答

0

我想我不明白一個不可變的Player類包含PlayerClass的原因。但無論如何,IMO你的Player類是什麼應該繼承Entity特質。不是用作模板(?)排序的PlayerClasses對象。因爲Player和類別如果不都是Entity,我認爲有Player這個點的意思?

您還以一種奇怪的方式混合了responsibilites/abstractions。這是什麼封裝在PlayerClassesPlayer? PlayerClasses看起來應該像「Rogue」一樣代表類的類型,而不是真正的玩家。爲此,它不應該有setter方法,也不是一個類類型的實體。 而初始化PlayerClasses對象的工廠類似於「壞」風格的方法。你應該總是試圖保證只基於類的類型,事情是正確的,沒有魔術方法需要調用的對象是正確的(即除了構造函數沒有init方法)。

以一個以PlayerClasses對象爲參數並且希望其他人使用該代碼的方法爲例。他們發現他們需要參考PlayerClass以及該類的無參數構造函數,但他們不知道所有初始化步驟是什麼。構造函數或各種工廠/構建器模式可以確保這一點。

這裏有一個如何我會做一個草稿:

interface PlayerClass { 
    int getBaseHp(); 
    int getBaseAtk(); 
    ... // more class attributes 
} 

// as utility so I don't have to write 20 full classes 
abstract class PlayerClassBase implements PlayerClass { 
    private final int hp, atk, ..; 
    protected PlayerClassBase(int hp, int atk, ...) { 
     this.hp = hp; 
     this.atk = atk; 
    } 
    @Override 
    public int getBaseHp() { 
     return hp; 
    } 
    .... 
} 

// short class but guaranteed that every instance of Rogue has the correct values 
class Rogue { 
    public Rogue() { 
     super(40, 23, 123, ...); 
    } 
} 

// something to represent entities 
interface Entity { 
    int getCurrentHp(); 
    int takeDamageFrom(Entity other); 
    ... 
} 

// maybe an abstract base class here as well 

// represents a player that has an immutable class and it can't exist without 
class Player implements Entity { 
    privte final PlayerClass playerClass; 
    private int currentHp; 
    ... 

    public Player(PlayerClass playerClass) { 
     this.playerClass = playerClass; 
     currentHp = playerClass.getHp(); 
     ... 
    } 
    public int takeDamageFrom(Entity other) { 
     currentHp -= other.getCurrentAtk(); 
     return currentHp; 
    } 

} 

的PlayerClass部分也可以是一個簡單enum,而不是一個大的類層次結構。

enum PlayerClass { 
    ROGUE(23, 23, 4, ...), 
    ... 
    ; 
    private final int hp; 
    PlayerClass(int hp, int atk, ...) { 
     this.hp = hp; 
     ... 
    } 
    public int getHp() { return hp; } 
    ... 
} 

這種方法你可以參考靜態和PlayerClass.ROGUE創建這樣一個球員:new Player(PlayerClass.ROGUE)。目前代替new Player(new PlayerClass().Rogue())。或與大等級:new Player(new Rogue())

相關問題