[英]How to define `health` and `maxHealth` in one object, when `healt` can't be higher than `maxHealth`?
我有一个名为Warrior
的类,它具有uint m_health
和uint m_maxHealth
属性。 我希望我的构造函数采用参数Warrior(uint health, uint maxHealth)
。
现在我已经学习了很多C ++并且我知道所有的语法等,但是很难找到关于如何使用这些东西等的教程。所以我真的不知道如何定义health
和maxHealth
当health
显然不能高于maxHealth
:/
以下是我想到的几种方法:
// method 1
Warrior::Warrior(uint health, uint maxHealth) :
m_health((health > maxHealth) ? maxHealth : health),
m_maxHealth(maxHealth)
{}
// method 2
Warrior::Warrior(uint health, uint maxHealth) :
m_maxHealth(maxHealth)
{
if (health > maxHealth) {
m_health = maxHealth;
}
else {
m_health = health;
}
}
我相信还有其他方法。 很抱歉,如果这只是一个意见问题,但如果在C ++中有一种“首选”方式,它会是什么?
如果你打算在游戏中设置健康状况,你可能需要考虑这样的事情:
Warrior::Warrior(unsigned int health, unsigned int maxHealth) :
m_maxHealth(maxHealth)
{
setHealth(health);
}
void Warrior::setHealth(unsigned int health)
{
m_health = std::min(health, m_maxHealth);
}
根据您对更好的定义,有一种“更好”的方式。 (我猜你的意思是“更短”)
Warrior::Warrior(unsigned int health, unsigned int maxHealth) :
m_health(std::min(health, maxHealth)),
m_maxHealth(maxHealth)
{
}
这实际上是关于界面设计的问题,而不是实际的实现。 代码中的两个实现都是类似的,并且实现了一个具有宽接口的设计,允许任何参数组合。
另一种方法是在构造函数上使用窄契约,其中只有在health < maxHealth
为真的明显约束时才能很好地定义对象的行为。 在这种情况下,您将记录构造函数并实现它:
Warrior::Warrior(unsigned int health, unsigned int maxHealth)
: m_health(health), m_maxHealth(maxHealth)
{
assert(health <= maxHealth);
}
在我看来,这是一个更好的设计。 没有充分的理由接受构造函数的错误参数。 通过在那里添加assert
,您可以在开发周期的早期检测到您的类型是否在合同之外使用。 这对于具有相同类型的多个参数的函数尤为重要,因为它有助于检测是否错误地将参数无序传递。 在那里使用广泛的合同会使maxHealth
与当前的health
相同,并且稍后你会在试图弄清楚Warrior
为什么比你认为的那样弱的时候遇到问题... 狭窄的合同会立刻告诉你参数乱序。
template <typename T>
class RangeBoundValue
{
public:
RangeBoundValue(const T _min, const T _max) : _min(_min), _max(_max) {}
void setValue(T val)
{
if (val < _min) _value = _min;
else if (val > _max) _value = _max;
else _value = val;
}
T value() const {return _value;}
private:
const T _min;
const T _max;
T _value;
};
在Warrior
使用这个助手类
class Warrior
{
...
private:
RangeBoundValue<uint> _health;
};
我会在不满足前提条件的情况下放置断言或抛出异常:
Warrior::Warrior(uint health, uint maxHealth) :
m_health(health),
m_maxHealth(maxHealth)
{
assert(health <= maxHealth);
// or throw exception
throw std::logic_error("explanation");
}
我的意思是,决定呼叫者的理性是什么? 如果调用者将健康值设置为大于maxHealth - 它违反了您的类逻辑,那么我建议立即失败并通知调用者。 它应该是软件中的问题,所以我认为隐藏它是不可取的。
异常或断言是一种明确的机制,可以帮助您尽早发现并识别此类问题。
我很惊讶当构造函数的参数列表提供了health> max_health时,人们建议抛出异常。 例如,假设您有一些复活实施,其中所有生物都恢复了固定的生命值,直到最大生命值,并且在某些情况下这超过了最大生命值,为避免耦合,您不希望此方法必须存储每个对象的最大的健康状况,您可以在将这些参数提交给构造函数之前添加测试它的方法,但这又会使事情变得复杂。 最大健康通常被实施为健康上限,并且鉴于这是一个简单的约束,与其他任何事物脱钩,应该是战士有责任强制执行自己的约束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.