8

我在一个类上有这两种方法,它们仅在一个方法调用上有所不同。显然,这是非常不干燥的,特别是因为两者都使用相同的公式。

int PlayerCharacter::getAttack() {
    int attack;
    attack = 1 + this->level;
    for(int i = 0; i < this->current_equipment; i++) {
        attack += this->equipment[i].getAttack();
    }
    attack *= sqrt(this->level);
    return attack;
}
int PlayerCharacter::getDefense() {
    int defense;
    defense = 1 + this->level;
    for(int i = 0; i < this->current_equipment; i++) {
        defense += this->equipment[i].getDefense();
    }
    defense *= sqrt(this->level);
    return defense;
}

我如何在 C++ 中整理它?

4

7 回答 7

18

一种简单的方法是在一个数组中表示一件设备的所有属性,由一个枚举索引。

enum Attributes {
  Attack, 
  Defense,
  AttributeMAX
};

class Equipment {
  std::vector<int> attributes;

  Equipment(int attack, int defense): attributes(AttributeMAX)
  {
    attributes[ATTACK] = attack;
    attributes[DEFENSE] = defense;
  }

};

然后你改变你的功能

int PlayerCharacter::getAttribute(int& value, Attribute attribute) {
    value = 1 + this->level;
    for(int i = 0; i <= current_equipment; i++) {
        value += this->equipment[i].attributes[attribute];
    }
    value *= sqrt(this->level);
    return value;
}

你可以这样称呼它

  player.getAttribute(player.attack, Attack);
于 2010-04-19T18:51:35.057 回答
12

在我看来,你所拥有的一切都很好,因为它可以让你更多地调整攻击/防御,而不是用一个功能来代表它们。一旦您开始测试您的游戏,您将开始平衡攻击/防御公式,因此为它们设置单独的函数就可以了。

DRY [不要重复自己] 的整个概念是 [希望] 防止您的代码成为巨大的复制和粘贴盛宴。在你的情况下,防御/攻击公式会随着时间而改变[例如,如果角色有增益/状态-疾病怎么办?特定的异常状态可能会将防御减半,同时增加 2 点攻击(狂暴,FF 参考,呵呵)]

于 2010-04-19T18:43:55.113 回答
6

从严格重构的角度来看,您可以这样做:

int PlayerCharacter::getDefense() {
    return getAttribute(&EquipmentClass::getDefense);
}

int PlayerCharacter::getOffense() {
    return getAttribute(&EquipmentClass::getOffense);
}

int PlayerCharacter::getAttribute(int (EquipmentClass::*attributeFun)()) {
    int attribute = 0;
    attribute= 1 + this->level;
    for(int i = 0; i <= current_equipment; i++) {
        attribute += this->equipment[i].*attributeFun();
    }
    attribute *= sqrt(this->level);
    return attribute;
}
于 2010-04-19T18:53:28.610 回答
5

好吧,我至少会考虑提取sqrt(this.level);为一个单独的函数,称为getLevelModifier()

defense = 1 + this.level;

attack = 1 + this.level;

可能

defense = getBaseDefense();

attack= getBaseAttack();

这不仅增加了灵活性,还自动记录了您的功能。

于 2010-04-19T18:51:51.777 回答
3

根据应用程序中的其他代码,它可能值得也可能不值得,但 OOP 方法将使防御和攻击值对象的类而不是普通的int. 然后,您可以从具有 get() 方法的公共基类派生它们,该方法根据需要调用由每个子类定义的虚拟 getEquipmentRate() 方法。

于 2010-04-19T19:22:59.207 回答
2

IMO,ItzWarty 提出了一个合理的观点——您可能只想不理会代码。假设您认为更改它是一件好事,您可以执行以下操作:

class equipment { 
public:
    int getAttack();
    int getDefense();
};

int PlayerCharacter::getBattleFactor(int (equipment::*get)()) { 
    int factor = level + 1;
    for (int i=0; i<current_equipment; ++i)
        factor += equipment[i].*get();
    return factor * sqrt(level + 1);
}

你会这样称呼它:

int attack = my_player.getBattleFactor(&equipment::getAttack);

或者:

int defense = my_player.GetBattleFactor(&equipment::getDefense);

编辑:

另一个明显的可能性是规定任何一件装备只能是防御性的或进攻性的。在这种情况下,事情变得更加简单,甚至可能会怀疑您是否真的需要一个函数:

class PlayerCharacter {
    std::vector<equipment> d_equip;
    std::vector<equipment> o_equip;

// ...

int d=level+1+std::accumulate(d_equip.begin(), d_equip.end(), 0)*sqrt(level+1);

int o=level+1+std::accumulate(o_equip.begin(), o_equip.end(), 0)*sqrt(level+1);
于 2010-04-19T18:59:07.737 回答
2

除了ltzWarty的回答,我建议将您的循环重构为一个函数以提高可读性:

int PlayerCharacter::getEquipmentAttack() {
    int attack = 0;
    for(int i = 0; i <= current_equipment; i++) {
        attack += this.equipment[i].getAttack();
    }
    return attack;
}
int PlayerCharacter::getAttack() {
    int attack = 1 + this->level;
    attack += getEquipmentAttack();
    attack *= sqrt(this->level);
    return attack;
}

此外,当您声明局部变量时,attack您应该立即对其进行初始化

于 2010-04-19T19:06:41.387 回答