这种反模式/代码气味有没有名称?

时间:2008-09-16 14:10:30

标签: design-patterns anti-patterns

首先我要说的是,我不提倡这种做法,但我最近才看到它,我想知道是否有一个名字,我可以用来指出有罪的一方。所以这里。

现在你有了一个方法,并且想要返回一个值。您想要返回错误代码。当然,异常是一个更好的选择,但无论出于何种原因,你想要一个错误代码。记住,我在这里扮演魔鬼的拥护者。所以你创建了一个泛型类,如下所示:

class FunctionResult<T>
{
    public T payload;
    public int result;
}

然后宣布你的功能如下:

FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

此模式的一个变体是使用枚举作为错误代码而不是字符串。现在,回到我的问题:这是否有一个名称,如果是,它是什么?

13 个答案:

答案 0 :(得分:17)

我同意这不是一个反模式。根据使用情况,它可能是一种气味。有理由为什么人们实际上不想使用例外(例如,对于初学者而言,返回的错误不是'例外')。

在某些情况下,您希望服务返回其结果的通用模型,包括错误和良好值。这可能由低级服务交互包装,将结果转换为异常或其他错误结构,但在服务级别,它允许服务返回结果和状态代码,而无需定义可能的异常结构。必须在远程边界上翻译。

此代码可能不一定是错误:考虑HTTP响应,它包含许多不同的数据,包括状态代码,以及响应的主体。

答案 1 :(得分:11)

答案 2 :(得分:10)

嗯,不是反模式。 C ++标准库利用了这一特性,.NET甚至在.NET框架中提供了一个特殊的FunctionResult类。它被称为Nullable。是的,这不仅限于功能结果,但它可以用于这种情况,在这里实际上非常有用。如果.NET 1.0已经有Nullable类,它肯定会用于NumberType.TryParse方法,而不是out参数。

答案 3 :(得分:6)

我通常将有效负载作为(非const)引用传递,并将错误代码作为返回值传递。

我是游戏开发者,我们放弃了例外

答案 4 :(得分:5)

Konrad是对的,C#一直使用双返回值。但我有点像C#中的TryParse,Dictionary.TryGetValue等方法。

int value;
if (int.TryParse("123", out value)) {
    // use value
}

而不是

int? value = int.TryParse("123");
if (value != null) {
    // use value
}

...主要是因为Nullable模式不能扩展到非Value返回类型(即类实例)。这不适用于Dictionary.TryGetValue()。并且TryGetValue比KeyNotFoundException更好(在调试器中没有“第一次机会异常”,可以说更高效),比Java的get()返回null更好(如果需要空值,那么),并且比必须更高效首先调用ContainsKey()。

但是 仍然有点棘手 - 因为这看起来像C#,那么它应该使用out参数。实例化课程可能会损失所有效率提升。

(可能是Java,除了“string”类型是小写的。在Java当然你必须使用一个类来模拟双返回值。)

答案 5 :(得分:4)

我不确定这是一种反模式。我经常看到这是出于性能原因使用而不是异常,或者可能是为了使方法可以更明确地失败。对我来说,这似乎是个人偏好而不是反模式。

答案 6 :(得分:3)

我同意那些说这不是反模式的人。它在某些情况下是完全有效的模式。例外情况适用于异常情况,应在预期情况下使用返回值(如示例中所示)。有些域期望来自类的有效和无效结果,并且这些结果都不应被建模为异常。

例如,给定X量的汽油,汽车可以从A到B,如果是这样,剩下多少汽油?这类问题非常适合您提供的数据结构。预计不能从A到B旅行,因此不应使用例外。

答案 7 :(得分:2)

这种方法实际上比我见过的其他方法要好得多。 C中的某些函数,例如,当它们遇到错误时,它们返回并且似乎成功。告诉他们失败的唯一方法是调用一个能得到最新错误的函数。

我花了好几个小时尝试在我的MacBook上调试信号量代码,然后我终于发现sem_init在OSX上不起作用!它编译时没有错误,运行时没有造成任何错误 - 但信号量不起作用,我无法弄清楚原因。我很遗憾将使用POSIX semaphores的应用程序移植到OSX并且必须处理已经调试过的资源争用问题。

答案 8 :(得分:1)

“无法判断这是否是错误”模式怎么样?好像如果你真的有一个例外但想要返回一个部分结果,你就把结果包装在异常中。

答案 9 :(得分:1)

如果您不想使用异常,最简单的方法是让函数返回错误/成功代码,并获取一个用结果填充的引用或指针参数。

我不会称之为反模式。这是一种经过充分验证的可行方法,通常比使用异常更可行。

答案 10 :(得分:1)

如果您希望您的方法偶尔失败,但不考虑那种例外,我更喜欢.NET Framework中使用的这种模式:

bool TryMyFunction(out FunctionResult result){    

     //...    
     result = new FunctionResult();
}

答案 11 :(得分:1)

关于气味和反模式的争论让我想起了“幸存者”电视节目,在那里你有各种各样的编程结构试图在岛外互相投票。我更愿意看到“构造X具有某种优点和缺点”,而不是不断发展的应该和不应该做的内容的列表。

答案 12 :(得分:0)

为了防止反模式指定,该代码有助于以某种方式使用:

  1. Object x = MyFunction()。payload; (忽略返回结果 - 非常糟糕)
  2. int code = MyFunction()。result; (扔掉有效载荷 - 如果这是预期用途可能没问题。)
  3. FunctionResult x = MyFunction(); // ... (一堆额外的FunctionResult对象和额外的代码来检查它们)
  4. 如果您需要使用返回代码,那很好。但是然后使用返回码。不要试图用它包装额外的有效载荷。这就是 ref out 参数(C#)的用途。可空类型可能是一个例外,但只是因为语言中有额外的糖来支持它。

    如果你仍然不同意这个评估,DOWNVOTE这个答案(不是整个问题)。如果你认为它是反模式,那么UPVOTE吧。我们将使用此答案来了解社区的想法。