繁体   English   中英

当`healt`不能高于`maxHealth`时,如何在一个对象中定义`health`和`maxHealth`?

[英]How to define `health` and `maxHealth` in one object, when `healt` can't be higher than `maxHealth`?

我有一个名为Warrior的类,它具有uint m_healthuint m_maxHealth属性。 我希望我的构造函数采用参数Warrior(uint health, uint maxHealth)

现在我已经学习了很多C ++并且我知道所有的语法等,但是很难找到关于如何使用这些东西等的教程。所以我真的不知道如何定义healthmaxHealthhealth显然不能高于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.

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