反模式-在接受数字参数的API函数中使用-1作为特殊值



考虑来自虚构游戏引擎API的示例函数:

function Entity.SetHealth( Number health )
  • 让这样的函数接受-1作为参数,在这种情况下导致实体变得不可战胜,这是不是很糟糕?

  • 我应该使用两个额外的函数:Entity.SetInvincibleEntity.GetInvincible吗?

请注意,这个具有不可战胜性和健康的例子实际上只是我编造的。

你可以做很多更糟糕的事情,我在许多游戏引擎和UI框架中经常看到这种方法,用于各种任务(例如,在重复动作的命令中,将repeats设置为-1意味着"永远重复")。如果你在其他方面都做得很好,那么批评这种设计选择将是一种挑剔。

也就是说,语义是非直观的(-1是不可战胜的?嗯?),所以最好有额外的函数。

幻数通常是一个坏兆头,但我不会说你应该禁止它们。换句话说,如果-1是一个非法值,那么可以使用它,但我至少会为它创建一个常量,这样对该方法的调用就会如下所示:

someEntity.SetHealth(Health.Infinite)

或者类似的,常数的命名由您决定。

然而,更好的方法(在我看来)是封装值,为其提供额外的数据,例如,您可以在C#中创建这样的类型:

public struct Health
{
    private readonly int _Value;
    public int Value { get { return _Value; } }
    public Health(int value)
    {
        if (value < 0 || value > SOME_ARBITRARY_MAX_NUMBER)
            throw new ArgumentOutOfRangeException("value");
        _Value = value;
    }
    public static Health Infinite
    {
        get
        {
            Health result = new Health(0);
            result._Value = -1;
            return result;
        }
    }
    public bool IsInfinite
    {
        get
        {
            return _Value == -1;
        }
    }
}

然后,您还可以添加必要的比较方法、运算符等,以便例如可以这样做:

Health a = Health.Infinite;
Health b = 100;               // automatic type coercion
if (b < a)                    // custom operator, knows that Infinite > *
    ...

相关内容

  • 没有找到相关文章

最新更新