簡體   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