简体   繁体   English

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

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

I have a class called Warrior that has uint m_health and uint m_maxHealth attributes. 我有一个名为Warrior的类,它具有uint m_healthuint m_maxHealth属性。 I want my constructor to take parameters Warrior(uint health, uint maxHealth) . 我希望我的构造函数采用参数Warrior(uint health, uint maxHealth)

Now I've studied C++ a lot and I know all the syntax etc, but it's hard to find tutorials on how to use the stuff etc. so I don't really know how should I define health and maxHealth when health obviously can't be higher than maxHealth :/ 现在我已经学习了很多C ++并且我知道所有的语法等,但是很难找到关于如何使用这些东西等的教程。所以我真的不知道如何定义healthmaxHealthhealth显然不能高于maxHealth :/

Here are few methods I thought of: 以下是我想到的几种方法:

// 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;
    }
}

I'm sure there are other ways too. 我相信还有其他方法。 Sorry if this is just an opinion question, but if there's a "preferred" way in C++, what would it be? 很抱歉,如果这只是一个意见问题,但如果在C ++中有一种“首选”方式,它会是什么?

If you intended to set the health during the game you might want to consider something like this: 如果你打算在游戏中设置健康状况,你可能需要考虑这样的事情:

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);
}

There is a "better" way, depending on your definition of better. 根据您对更好的定义,有一种“更好”的方式。 (And I'm guessing you mean "shorter" here) (我猜你的意思是“更短”)

Warrior::Warrior(unsigned int health, unsigned int maxHealth) :
    m_health(std::min(health, maxHealth)),
    m_maxHealth(maxHealth)
{
}

This is really more of a question on the design of the interface than the actual implementation. 这实际上是关于界面设计的问题,而不是实际的实现。 Both of the implementations in your code are similar and implement a design with a wide interface that allows for any combination of arguments. 代码中的两个实现都是类似的,并且实现了一个具有接口的设计,允许任何参数组合。

A different approach would be to use a narrow contract on your constructor, in which the behavior of the object is well defined only if the obvious constraint that health < maxHealth is true. 另一种方法是在构造函数上使用契约,其中只有在health < maxHealth为真的明显约束时才能很好地定义对象的行为。 In that case you would document the constructor as such and implement it: 在这种情况下,您将记录构造函数并实现它:

Warrior::Warrior(unsigned int health, unsigned int maxHealth)
  : m_health(health), m_maxHealth(maxHealth)
{
   assert(health <= maxHealth);
}

Which in my opinion is a better design. 在我看来,这是一个更好的设计。 There is no good reason to accept the wrong arguments to the constructor. 没有充分的理由接受构造函数的错误参数。 By adding that assert there you can detect early in the development cycle when your type is used out of contract. 通过在那里添加assert ,您可以在开发周期的早期检测到您的类型是否在合同之外使用。 This is specially important with functions that have multiple arguments of the same type, as it will help detect if by mistake you pass the arguments out of order. 这对于具有相同类型的多个参数的函数尤为重要,因为它有助于检测是否错误地将参数无序传递。 The use of a wide contract there would reduce the maxHealth to be the same as the current health , and at a later time you will have problems trying to figure out why the Warrior is weaker than you thought it should be... the narrow contract will tell you the arguments are out of order immediately. 在那里使用广泛的合同会使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;
};

Use this helper class inside Warrior Warrior使用这个助手类

class Warrior
{
...
private:
    RangeBoundValue<uint> _health;
};

I would just put an assertion or throw exception in case precondition is not met: 我会在不满足前提条件的情况下放置断言或抛出异常:

Warrior::Warrior(uint health, uint maxHealth) :
    m_health(health),
    m_maxHealth(maxHealth)
{
    assert(health <= maxHealth); 
    // or throw exception
    throw std::logic_error("explanation");
}

I mean, what is the rational to decide for the caller which value to take? 我的意思是,决定呼叫者的理性是什么? If caller puts health value bigger than maxHealth - it's violation of your class logic, so I would propose to fail immediately and inform caller about this. 如果调用者将健康值设置为大于maxHealth - 它违反了您的类逻辑,那么我建议立即失败并通知调用者。 It should be problem in the software, so I think it's not desirable to hide it. 它应该是软件中的问题,所以我认为隐藏它是不可取的。

Exception or assertion is an explicit mechanism that will help you to find and recognise such problems early. 异常或断言是一种明确的机制,可以帮助您尽早发现并识别此类问题。

I am quite surprised that people are suggesting to throw exceptions when an argument list to the constructor is supplied with health>max_health. 我很惊讶当构造函数的参数列表提供了health> max_health时,人们建议抛出异常。 For instance, say you have some resurrection implementation where all creatures are resurrected with a fixed amount of health up to their maximum health and in some cases this exceeds maximum health, to avoid coupling you don't want this method to have to store every object's maximum health, you could add methods to test for it before submitting these arguments to the constructors but again this complicates things. 例如,假设您有一些复活实施,其中所有生物都恢复了固定的生命值,直到最大生命值,并且在某些情况下这超过了最大生命值,为避免耦合,您不希望此方法必须存储每个对象的最大的健康状况,您可以在将这些参数提交给构造函数之前添加测试它的方法,但这又会使事情变得复杂。 Max health is usually implemented as a ceiling on health and given that this is a simple constraint, uncoupled from anything else, it should be the warrior's responsibility to enforce its own constraints. 最大健康通常被实施为健康上限,并且鉴于这是一个简单的约束,与其他任何事物脱钩,应该是战士有责任强制执行自己的约束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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