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

问题描述 投票:19回答:13

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

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

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

然后声明你的函数:

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

    return result;
}

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

design-patterns anti-patterns
13个回答
17
投票

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

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

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


1
投票

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

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


1
投票

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

bool TryMyFunction(out FunctionResult result){    

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

1
投票

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


0
投票

为了防止反模式指定,该代码适用于以下几种方式:

  1. 对象x = MyFunction()。payload; (忽略返回结果 - 非常糟糕)
  2. int code = MyFunction()。result; (扔掉有效载荷 - 如果这是预期用途可能没问题。)
  3. FunctionResult x = MyFunction(); // ...(一堆额外的FunctionResult对象和额外的代码来检查它们的位置)

如果你需要使用返回码,那没关系。但是然后使用返回码。不要试图用它包装额外的有效载荷。这就是ref和out参数(C#)的用途。可空类型可能是一个例外,但只是因为语言中有额外的糖来支持它。

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


11
投票

10
投票

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


6
投票

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

我是游戏开发者,我们消除异常


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当然你必须使用一个类来模拟双返回值。)


4
投票

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


3
投票

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

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


2
投票

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

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


1
投票

如何“无法判断这是否是一个错误”模式。看起来如果你真的有一个例外但想要返回一个部分结果,你将结果包装在异常中。

© www.soinside.com 2019 - 2024. All rights reserved.