2015-10-18 111 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())