首页 / 知识

这种反模式/代码气味有名字吗?

2023-04-15 22:53:00

这种反模式/代码气味有名字吗?

Is there a name for this anti-pattern/code smell?

首先,我说我不主张采用这种方法,但是最近我看到了这种方法,我想知道是否有一个名字可以用来指认有罪的政党。 所以去。

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

1
2
3
4
5
class FunctionResult< T >
{
    public T payload;
    public int result;
}

然后像这样声明你的函数:

1
2
3
4
5
6
7
FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

此模式的一种变体是对错误代码使用枚举而不是字符串。 现在,回到我的问题:对此有一个名称吗?


我同意这不是专门的反模式。根据使用情况,可能会有异味。有一些原因导致人们实际上不希望使用异常(例如,对于初学者来说,返回的错误不是" exception")。

在某些情况下,您希望服务为其结果返回一个通用模型,包括错误和良好值。这可能被低级服务交互所包装,该服务交互将结果转换为异常或其他错误结构,但是在服务级别,它使服务可以返回结果和状态代码,而不必定义可能会导致异常的异常结构。必须跨远程边界进行翻译。

该代码也不一定是错误:考虑一个HTTP响应,该响应由许多不同的数据(包括状态码)以及响应主体组成。


它被称为"用异常替换错误代码"


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


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

我是游戏开发人员,我们排除了例外情况


Konrad是正确的,C#始终使用双返回值。但是我有点像C#中的TryParse,Dictionary.TryGetValue等方法。

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

代替

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

...主要是因为Nullable模式无法缩放为非Value返回类型(即类实例)。这不适用于Dictionary.TryGetValue()。而且TryGetValue不仅比KeyNotFoundException(在调试器中始终没有"第一次机会异常",可以说效率更高)要好,比Java的get()返回null(如果期望null值会怎样)的做法还好,并且比必须这样做要更有效。首先调用ContainsKey()。

但这仍然有些棘手-因为它看起来像C#,所以应该使用out参数。实例化类可能会损失所有效率提高。

(除了" string"类型为小写字母外,它可以是Java。在Java中,您当然必须使用一个类来模拟双返回值。)


我不确定这是否是反模式。出于性能原因,我经常看到使用此方法而不是使用异常,或者可能是为了使该方法失败的事实更加明确。在我看来,这似乎是个人喜好而不是反模式。


我同意那些说这不是反模式的人的观点。在某些情况下,这是一种完全有效的模式。在特殊情况下例外,应在预期情况下使用返回值(如您的示例中所示)。一些域期望类产生有效和无效的结果,并且都不应该将它们建模为异常。

例如,给定X倍的汽油量,一辆汽车可以从A到B行驶吗?如果有,还剩下多少汽油?对于您提供的数据结构,这种问题是理想的。预计无法进行从A到B的旅行,因此不应使用异常。


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

我花了数小时尝试在MacBook上调试信号灯代码,然后才终于发现sem_init在OSX上不起作用!它编译时没有错误,并且在运行时没有引起任何错误-但是该信号灯不起作用,我不知道为什么。我很感激那些将使用POSIX信号的应用程序移植到OSX并必须处理已经调试的资源争用问题的人们。


关于气味和反模式的辩论让我想起了"幸存者"电视节目,那里有各种各样的编程结构试图在岛上互相投票。我宁愿看到" construct X具有某种优缺点",而不是不断发展的关于应该做什么和不应该做什么的法令列表。


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

1
2
3
4
5
bool TryMyFunction(out FunctionResult result){    

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

如果您不想使用异常,则最干净的方法是让函数返回错误/成功代码,并采用填充了结果的引用或指针参数。

我不会称其为反模式。这是一种行之有效的可行方法,通常比使用异常更好。


"无法确定这是否是错误"模式如何呢?好像您确实有异常,但想返回部分结果,则将结果包装在异常中。


为了反模式的指定,该代码可以通过以下几种方式使用:

  • 对象x = MyFunction()。payload; (忽略返回结果-非常糟糕)
  • int代码= MyFunction()。result; (扔掉有效载荷-如果这是预期用途,可能会没事的。)
  • FunctionResult x = MyFunction(); // ...(一堆额外的FunctionResult对象和额外的代码来检查它们)
  • 如果您需要使用返回码,那很好。但是,然后使用返回码。不要尝试在其中打包额外的负载。这就是ref和out参数(C#)的目的。可空类型可能是一个例外,但这仅是因为在语言中还增加了额外的糖来支持它。

    如果您仍然不同意此评估,请对这个答案(不是整个问题)进行投票。如果您确实认为这是一种反模式,请对其进行投票。我们将使用此答案来查看社区的想法。


    模式错误代码选择方法

    最新内容

    相关内容

    猜你喜欢