我在一个只有一个方法调用不同的类上有这两个方法。显然,这是非常不干的,特别是因为两者都使用相同的公式。
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 ++中整理它?
答案 0 :(得分: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);
答案 1 :(得分:12)
在我看来,你所拥有的一切都很好,因为它可以让你更多地调整攻击/防御,而不是用一个函数代表它们。一旦你开始测试你的游戏,你将开始平衡攻击/防御公式,所以为它们提供单独的功能是好的。
DRY [不重复自己]的整个概念[希望]可以防止你的代码成为一个庞大的副本&amp;粘贴节日。在你的情况下,防御/攻击公式会随着时间而改变[例如,如果角色有buff /状态 - 疾病怎么办?特定状态疾病可能会将防御减少一半,同时将攻击力提高2(Berserk,FF参考,heh)]
答案 2 :(得分: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;
}
答案 3 :(得分:5)
好吧,我至少会考虑将sqrt(this.level);
解压缩为一个名为getLevelModifier()
的单独函数
和
defense = 1 + this.level;
attack = 1 + this.level;
可能是
defense = getBaseDefense();
attack= getBaseAttack();
这不仅增加了灵活性,还自动记录您的功能。
答案 4 :(得分:3)
根据应用程序中的其他代码,它可能或可能不值得,但OOP方法会使类的防御和攻击值对象而不是普通的int
。然后,您可以从具有get()方法的公共基类派生它们,该方法根据需要调用由每个子类定义的虚拟getEquipmentRate()方法。
答案 5 :(得分: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);
答案 6 :(得分: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
时,您应该initialize it immediately。