繁体   English   中英

这是建立类层次结构的正确方法吗?

[英]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类有什么意义?

您还以奇怪的方式混合了职责/抽象。 PlayerClassesPlayer封装的是什么? PlayerClasses看起来应该代表“ Rogue”之类的类类型,而不是实际的玩家。 为此,它不应具有setter方法,也不应该是类类型的实体。 初始化PlayerClasses对象的类似工厂的方法是“不良”样式。 您应该始终尝试仅基于类类型保证事情是正确的,而没有魔术对象需要调用的方法才是正确的(即,除了构造函数之外,没有init方法)。

例如,采用一个将PlayerClasses对象作为参数的方法,并且您希望其他人使用该代码。 他们看到他们需要引用PlayerClassPlayerClass的无参数构造函数,但是他们不知道所有初始化步骤是什么。 构造函数或各种工厂/构造器模式可以保证这一点。

这是我将如何完成的草稿:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM