[英]Is this the correct way to build class hierarchy?
好的,所以我有整个模块负责在游戏中生成玩家类,并且经过数小时的辛苦工作后,我想到了这个层次结构(代码片段没有使其过于图形化,但仍然可以继续进行)
我有一个用于实体(玩家或怪物)的基本接口:
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变量,然后用相同的变量提取名称空间并不是一种可行的方法。
我想我不理解包含PlayerClass
的不可变Player
类的PlayerClass
。 但不管怎么说,IMO你的Player
类是什么应该继承Entity
特质。 不是用作模板(?)的PlayerClasses
对象。 因为拥有一个Player
和一个我假设不是两个Entity
构造相似的Monster
类有什么意义?
您还以奇怪的方式混合了职责/抽象。 PlayerClasses
和Player
封装的是什么? PlayerClasses看起来应该代表“ Rogue”之类的类类型,而不是实际的玩家。 为此,它不应具有setter方法,也不应该是类类型的实体。 初始化PlayerClasses对象的类似工厂的方法是“不良”样式。 您应该始终尝试仅基于类类型保证事情是正确的,而没有魔术对象需要调用的方法才是正确的(即,除了构造函数之外,没有init方法)。
例如,采用一个将PlayerClasses
对象作为参数的方法,并且您希望其他人使用该代码。 他们看到他们需要引用PlayerClass
和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())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.