您如何称呼这种(反?)模式,其中每个操作 returns 结果的实例 class?
How do you call this (anti?)pattern where every operation returns an instance of a result class?
以下(反?)模式有名称吗?
- 每个函数 returns 至少具有以下两个 public 变量的
result
class(或结构或关联数组)的实例:
success
:如果操作成功完成,true/false 值
result
:保存函数结果的变量,如果函数为 void,则不保存任何内容。
- 如果
success
是 false
,则 error
变量可能包含有关错误的信息(exception/stack trace/debug)
- 如果
error
不为空 ,则可以定义一个 message
变量来保存用户友好的消息
- 只封装了运算结果。输入正常通过。
我在 .Net 和 PHP 中都看到过这种用法(在服务器上和在 JavaScript/Ajax 请求调用的脚本中)。这是最佳实践吗?这是反模式吗?
这是处理可以 return 失败或成功和值的过程调用的常用方法。如评论中所述,调用 API 时很常见。备选方案包括:a) 将 return 值与 success/failure 组合,因此必须在调用代码中从外部知道并检查它,b) 使用输出参数 return 上的所需值成功,或 c) 抛出异常以指示失败,这是昂贵且愚蠢的,所以我不会进一步讨论。
a) 将 return 值与 Success/Failure
组合
这要求调用代码知道什么代表 return 值中的失败,而不是被明确告知失败。
public string GetSomeString(int id)
{
//return a value on success or null on failure
}
因此调用代码必须知道 null 或空字符串失败并进行相应检查...
var result = obj.GetSomeString(2);
if(string.IsNullOrEmpty(result))
{
//ooops, failed
}
当然,如果 null 是一个合法的 return 值,这不是一个选项。
与 int 调用类似...
public int GetSomeInt(string someArg, bool someOtherArg)
{
//return a value or a -1 for failure
}
所以调用代码必须再次知道什么是坏的,并假设其他一切都正常...
var result = obj.GetSomeInt("blah", true);
if(result == -1)
{
//ooops, failed
}
再一次,如果您的 "error" 值在某些情况下是合法的(或者更糟的是稍后变得合法),则它不起作用。
b) 使用输出参数在成功时传回一个值
另一个选项是 return 方法的成功或失败,如果成功则使用输出参数 return 值。
public bool GetSomeString(int id, out string someString)
{
//if fail return false
//otherwise set someString = value and return true
}
所以调用代码是这样的...
string goodString = null;
if(!obj.GetSomeString(2, out goodString))
{
//ooops, something bad happened
}
这提供了将调用的 success/failure 与其值 return 分开的优势。它有效,但它是一种笨拙的语法,如果您需要 return 多于值,您将最终添加更多输出参数或创建一个对象到 return 无论如何。它也无法告诉您失败的原因。这让我们回到您问题的主题...
使用结果对象
这为您提供了 b) 的优势,因为 success/failure 是明确的,并且不需要调用代码知道什么 return 值可能表示失败。它感觉更干净,因为它不需要使用 out 语法。它还提供了额外的好处,允许您通过在结果对象的消息 属性 中将其传回来指示失败的原因。
以下(反?)模式有名称吗?
- 每个函数 returns 至少具有以下两个 public 变量的
result
class(或结构或关联数组)的实例:success
:如果操作成功完成,true/false 值result
:保存函数结果的变量,如果函数为 void,则不保存任何内容。
- 如果
success
是false
,则error
变量可能包含有关错误的信息(exception/stack trace/debug) - 如果
error
不为空 ,则可以定义一个 - 只封装了运算结果。输入正常通过。
message
变量来保存用户友好的消息
我在 .Net 和 PHP 中都看到过这种用法(在服务器上和在 JavaScript/Ajax 请求调用的脚本中)。这是最佳实践吗?这是反模式吗?
这是处理可以 return 失败或成功和值的过程调用的常用方法。如评论中所述,调用 API 时很常见。备选方案包括:a) 将 return 值与 success/failure 组合,因此必须在调用代码中从外部知道并检查它,b) 使用输出参数 return 上的所需值成功,或 c) 抛出异常以指示失败,这是昂贵且愚蠢的,所以我不会进一步讨论。
a) 将 return 值与 Success/Failure
组合这要求调用代码知道什么代表 return 值中的失败,而不是被明确告知失败。
public string GetSomeString(int id)
{
//return a value on success or null on failure
}
因此调用代码必须知道 null 或空字符串失败并进行相应检查...
var result = obj.GetSomeString(2);
if(string.IsNullOrEmpty(result))
{
//ooops, failed
}
当然,如果 null 是一个合法的 return 值,这不是一个选项。
与 int 调用类似...
public int GetSomeInt(string someArg, bool someOtherArg)
{
//return a value or a -1 for failure
}
所以调用代码必须再次知道什么是坏的,并假设其他一切都正常...
var result = obj.GetSomeInt("blah", true);
if(result == -1)
{
//ooops, failed
}
再一次,如果您的 "error" 值在某些情况下是合法的(或者更糟的是稍后变得合法),则它不起作用。
b) 使用输出参数在成功时传回一个值
另一个选项是 return 方法的成功或失败,如果成功则使用输出参数 return 值。
public bool GetSomeString(int id, out string someString)
{
//if fail return false
//otherwise set someString = value and return true
}
所以调用代码是这样的...
string goodString = null;
if(!obj.GetSomeString(2, out goodString))
{
//ooops, something bad happened
}
这提供了将调用的 success/failure 与其值 return 分开的优势。它有效,但它是一种笨拙的语法,如果您需要 return 多于值,您将最终添加更多输出参数或创建一个对象到 return 无论如何。它也无法告诉您失败的原因。这让我们回到您问题的主题...
使用结果对象
这为您提供了 b) 的优势,因为 success/failure 是明确的,并且不需要调用代码知道什么 return 值可能表示失败。它感觉更干净,因为它不需要使用 out 语法。它还提供了额外的好处,允许您通过在结果对象的消息 属性 中将其传回来指示失败的原因。