Class 我应该如何设计具有大量属性的游戏角色类?
我是一名学生,目前正在学习Java,并试图用它编写一个基于文本的小型RPG游戏。我在游戏设计中遇到的第一个问题是“角色”类,它代表所有可玩的英雄和敌人角色,现在由我自己实现如下:Class 我应该如何设计具有大量属性的游戏角色类?,class,attributes,Class,Attributes,我是一名学生,目前正在学习Java,并试图用它编写一个基于文本的小型RPG游戏。我在游戏设计中遇到的第一个问题是“角色”类,它代表所有可玩的英雄和敌人角色,现在由我自己实现如下: class RPGActor { private String name; private int HP; // hit points private int MP; // mana private int AP; // attack private int DP; // defense ... // follow
class RPGActor {
private String name;
private int HP; // hit points
private int MP; // mana
private int AP; // attack
private int DP; // defense
... // followed by tens of other attributes.
public Actor(int actorID)
{
... // Reads all attributes from a file based on the 'actorID'.
}
public void printStatus()
{
System.out.println(name);
System.out.println("HP :" + HP);
System.out.println("MP :" + MP);
... // And print all the attributes one by one.
}
public void setHP(int newHP)
{
HP = newHP;
}
public int getHP()
{
return HP;
}
public void setMP(...)
{
...
}
// And tens of accessors and mutators for each attribute
}
我看到这个设计的问题是有太多的东西需要手工编码:类中有20-30个属性,需要为每个属性实现一个单独的访问器/变异器。用于显示英雄当前状态的函数printStatus必须单独输出每个属性,即使输出的每一行都遵循完全相同的格式。这使得类定义冗长乏味
另外,如果以后我想在游戏中再添加一个属性,那么我必须记住修改“printStatus”,并为它添加一对访问器/变异器
所以我的问题是:有没有一种方法可以设计类,这样我就可以使用一对set/get函数来设置所有属性。比如:
public void set(String attribName, int attribVal)
{
...
}
并按如下方式迭代打印属性:
public void printStatus()
{
System.out.println(name);
for (...)
System.out.println(curAttribName + ": " + curAttribVal);
}
class RPGActor {
private String name;
private int HP; // hit points
private int MP; // mana
private int AP; // attack
private int DP; // defense
// ... followed by tens of other attributes.
private Map<String, Object> attributes = new HashMap<String, Object>();
public RPGActor(int actorID) {
// ... Reads all attributes from a file based on the 'actorID'.
}
public void attacks(RPGActor defender) {
defender.defend(this.getAttack());
}
public void defend(Attack attack) {
switch (attack.getType()) {
case PHYSICAL:
// This actor is resistant against physical attacks.
return;
case MAGICAL:
this.HP = this.HP - attack.getStrength();
break;
}
}
public void castSpell(Spell spell, Set<Target> targets) {
// targets could be other actors, equipment or chickens dependent on the spell
// ...
}
}
多谢各位 我将向您展示一个解决方案,用一个方法设置所有属性,但您不应该使用它,我将在后面告诉您原因
class RPGActor {
private static final String NAME = "Name";
private static final String HP = "HP";
private static final String MP = "MP";
private static final String AP = "AP";
private static final String DP = "DP";
// ... followed by tens of other attributes.
private Map<String, Object> attributes = new HashMap<String, Object>();
public RPGActor(int actorID) {
this.attributes.put(NAME, nameFromFile);
// ... Reads all attributes from a file based on the 'actorID'.
}
public void setAttribute(String attributeName, Object value) {
this.attributes.put(attributeName, value);
}
public int getAttribute(String attributeName) {
return this.attributes.get(attributeName);
}
}
类RPGActor{
私有静态最终字符串NAME=“NAME”;
私有静态最终字符串HP=“HP”;
私有静态最终字符串MP=“MP”;
私有静态最终字符串AP=“AP”;
私有静态最终字符串DP=“DP”;
//…然后是数十个其他属性。
私有映射属性=新HashMap();
公共RPGActor(int actorID){
this.attributes.put(NAME,nameFromFile);
//…基于“actorID”从文件中读取所有属性。
}
public void setAttribute(字符串attributeName,对象值){
this.attributes.put(attributeName,value);
}
public int getAttribute(字符串attributeName){
返回this.attributes.get(attributeName);
}
}
这有几个缺点:
- 没有设置特定属性的代码完成
- 可读性较差
更好: 尽管您使用的是类和对象,但这并不是很好。尤其是你违反了法律 您不应该从类本身之外显式设置HP。仅在少数需要的用例中。相反,你应该考虑演员真正做什么:攻击、防守、施法 因此,它应该更像这样:
public void printStatus()
{
System.out.println(name);
for (...)
System.out.println(curAttribName + ": " + curAttribVal);
}
class RPGActor {
private String name;
private int HP; // hit points
private int MP; // mana
private int AP; // attack
private int DP; // defense
// ... followed by tens of other attributes.
private Map<String, Object> attributes = new HashMap<String, Object>();
public RPGActor(int actorID) {
// ... Reads all attributes from a file based on the 'actorID'.
}
public void attacks(RPGActor defender) {
defender.defend(this.getAttack());
}
public void defend(Attack attack) {
switch (attack.getType()) {
case PHYSICAL:
// This actor is resistant against physical attacks.
return;
case MAGICAL:
this.HP = this.HP - attack.getStrength();
break;
}
}
public void castSpell(Spell spell, Set<Target> targets) {
// targets could be other actors, equipment or chickens dependent on the spell
// ...
}
}
类RPGActor{
私有字符串名称;
private int HP;//生命值
私有int MP;//法力
私有int-AP;//攻击
私有int-DP;//防御
//…然后是数十个其他属性。
私有映射属性=新HashMap();
公共RPGActor(int actorID){
//…基于“actorID”从文件中读取所有属性。
}
公共空间攻击(RPGActor defender){
defender.defect(this.getAttack());
}
公共虚空防御(攻击){
开关(attack.getType()){
个案物理:
//这个演员能抵抗物理攻击。
返回;
案例:
this.HP=this.HP-attack.getStrength();
打破
}
}
公共虚空施法(法术,设定目标){
//目标可能是其他演员、装备或依赖于咒语的小鸡
// ...
}
}
使用或更高级的设计模式,例如,您可以让每个参与者对攻击做出不同的反应。让我想起了Zork……非常感谢您的回答!它被设计成这样的原因是,实际上还有另一个类,叫做地下城主,处理所有的攻击/防御/施法事件。例如,当攻击发生时,地下城主会决定攻击者/防御者是谁以及他应该损失多少生命(防御者不知道他为什么会损失生命)。我相信你的第二个解决方案确实是一个更优雅的设计。但是你能详细解释一下为什么原始设计违反了封装吗?我认为封装意味着属性对用户是不可见的,这是由“私有”保证的。你的地下城主人实际上是一个。它集中了太多关于攻击、防御、法术、生物等方面的知识。。。在我看来,防御者不知道他为什么会失去生命是一种误解,因为防御者可能拥有护甲或抵抗力,因此生命损失取决于个体生物,因此应由防御者处理(但也可以设计不同,这不是唯一的解决方案)封装并不像将属性私有化那么简单,但它是一种共识,如果我开始编程时也这么认为的话。封装范式是将逻辑和属性集中在一个地方,并尽可能限制外部访问。相比之下,将属性设置为HP私有,但提供getter和setter以无任何限制地对其进行操作,并不封装属性或逻辑,这只是访问属性的另一种方式。另一个重要方面是可维护性。如果你决定改变生物保护自己的方式,我认为RPGActor必须改变。但也许我得换个角色扮演者和地下城主。这在一开始并不是问题,但随着您添加更多功能,它逐渐变得更加混乱。你应该读一读这本书。有很多关于面向对象编程的好书,但大多数范例在维基百科上都有很好的描述。花点时间通读重要的部分。非常感谢你的解释。它澄清了很多事情。我在学校还没有真正学到任何关于设计模式的深刻知识,所以RPGActor/undgeonmaster设计是最好的