【问题标题】:Using return statements to great effect!使用 return 语句效果很好!
【发布时间】:2009-03-04 06:44:47
【问题描述】:

当我创建带有返回值的方法时,我通常会尝试进行设置,以便永远不会出现以必须返回某个默认值的方式调用该方法的情况。当我开始时,我经常会编写一些方法来做某事,并且要么返回他们所做的事情,要么如果他们没有做任何事情,就会返回 null。但我讨厌在我的代码中使用丑陋的 if(!null) 语句,

我正在阅读我多年前阅读的实用程序员的 ruby​​ 重新指南,我注意到他们经常返回 self(ruby 的 this),而他们通常不会返回任何内容。他们说,这是为了能够链接方法调用,如本例中使用的 setter,该 setter 返回其设置的属性的对象。

tree.setColor(green).setDecor(gaudy).setPractical(false)

最初我觉得这种东西很有吸引力。有几次我很高兴能够链接方法调用,比如Player.getHand().getSize(),但这有点不同,因为方法调用的对象一步一步地变化。

堆栈溢出如何看待返回值?当您想到返回值时,是否有任何模式或习语会温暖地浮现在脑海中?有什么好方法可以避免挫折和增加美感?

【问题讨论】:

  • 哇!我的问候已从这篇文章中删除。这是因为问候与科学无关吗?我通常在帖子开头说“hi”和“z”。在最后。我认为做我自己是可以的,但不是吗?我想我应该停止编造单词并输入“?”在语句的末尾也是这样吗?
  • @Ziggy:是的,如果您以后将这些内容从帖子中删除,我们将不胜感激。谢谢。
  • 在这里,我为您修复了一个实际错误。

标签: coding-style methods return-value fluent-interface


【解决方案1】:

以我的拙见,您应该考虑三种退货情况:

对象属性操作

首先是对象属性的操作。您在此处描述的模式在操作对象时经常使用。一个非常典型的场景是与工厂一起使用它。考虑这个假设的创造调用:

// When the object has manipulative methods:
Pizza p = PizzaFactory().create().addAnchovies().addTomatoes(); 
// When the factory has manipulative methods working on the 
// object, IMHO more elegant from a semantic point of view:
Pizza p = PizzaFactory().create().addAnchovies().addTomatoes().getPizza();

它允许快速掌握正在创建的确切内容或如何操作对象,因为这些方法形成了一个人类可读的表达式。这绝对不错,但不要过度使用。一个经验法则是,这可能与返回值也可以声明为 void 的方法一起使用。

评估对象属性

第二个可能是当方法评估对象上的某些内容时。例如,考虑car.getCurrentSpeed() 方法,它可以被解释为向对象询问当前速度并返回的消息。它只会返回值,不会太复杂。 :)

让对象做这个或那个

第三个可能是当一个方法执行一个操作时,返回某种值,表明调用者的意图得到了多大的满足——但布局这样一个方法可能很困难:

int new_gear = 20;
if (car.gears.changeGear(new_gear)) // does that mean success or fail?

这是您可以看到设计方法的困难之处。它应该在成功还是失败时返回 0?如果无法设置档位,-1 怎么样,因为汽车只有 5 个档位?这是否意味着当前档位现在也处于-1?该方法可以返回它更改为的齿轮,这意味着您必须将提供给该方法的参数与返回代码进行比较。那会奏效。另一方面,您可以简单地返回 true 或 false 表示失败,或者返回 false 或 true 表示失败。可以通过估计您是否希望这些方法调用失败或成功来决定使用哪一个。

以我的拙见,有一种方法可以更好地表达此类返回值的语义,即为它们提供语义描述。未来与您的对象交互的开发人员会喜欢您,因为您不必为您的方法查找 cmets 或文档:

class GearSystem {
// (...)
public:
enum GearChangeResult
{ GearChangeSuccess, NonExistingGear, MechanicalGearProblem };

GearChangeResult changeGear (int gear);
};

这样,对于任何查看您的代码的程序员来说,返回值的含义都变得非常明显(考虑:if (gears.changeGear(20) == GearSystem::GearChangeSuccess) - 比上面的示例更清楚)

反模式:失败作为返回码。

我实际上省略了返回值的第四种可能性,因为在我看来它不是任何一种:当你的程序中有错误时,比如逻辑错误或需要处理的失败 - 你理论上可以返回一个表明如此的值。但今天,这种做法不再经常发生(或不应该如此),因为有例外。

【讨论】:

  • 失败的返回码不是用得这么频繁吗?整个 WindowsAPI 都充满了这些。即使在 .net 中也有很多这样的情况,只是因为异常需要大量的处理器周期才能被抛出。以 TryParse() 方法为例。
  • 我尝试让操作失败引发异常。根据上面的示例,业务逻辑中的失败可以通过返回来描述。程序错误(即向函数调用方法的函数提供空对象)会抛出异常恕我直言。
  • WRT 异常速度:好的,但是我们还必须删除 OOP 的许多功能,以保持“快速”。哦,函数调用也会增加开销。 :-) 我使用大量数据集,速度(或缺乏)在于数据结构和算法,而不是堆栈展开。 CPU 很便宜,工时不是。
  • 啊,另一个可以说明问题的例子:考虑一个 3D 射击游戏。用户可能会不断地靠墙奔跑。程序碰撞检测的结果将是发生碰撞,用户无法进一步行走 - 就像在第三个街区中一样。
  • 然后考虑一个墙列表,其中包含指向几何图形的指针,这些指针提供给进行交叉测试的方法。该方法将返回指示是否有任何交叉点。现在,例如,如果其中一堵墙有一个 NULL 指针作为几何图形,那就是程序错误,就像在反模式中一样。
【解决方案2】:

我不同意方法永远不应该返回 null。最明显的例子来自系统编程。例如,如果有人要求打开一个文件,如果打开失败,您只需给他们 null。没有明智的选择。在链表的最后一个节点上调用时,还有其他适用于 null 的情况,例如 getNextNode(node) 方法。所以我猜这些情况的共同点是 null 代表“没有对象”(没有文件句柄或没有列表节点),这是有道理的。

在其他情况下,该方法永远不会失败,并且有适当的异常工具。然后,我认为像您的示例这样的方法链接可以起到很好的作用。我认为您似乎认为这是“实用程序员”的创新,这有点可笑。事实上,如果不是更早的话,它可以追溯到 Lisp。

【讨论】:

  • 你能举一个 Lisp 中方法链的例子吗?我还没有在 Lisp 中看到过这样的事情(Clojure 除外,但 Clojure 是一种最近的语言)。它可能来自 Smalltalk:它对此有特殊的语法(分号)。
  • 我希望我没有给人留下将方法链接归因于 PP 的印象。那就是我第一次看到它的地方。我注意到我的朋友 Jon 经常使用面向对象编程:真是个天才!
  • 只是我的 2cents,但我希望打开文件代码在这种情况下引发异常。除非它是更高级别的代码。
【解决方案3】:

返回this也用在“构建器模式”中,这是另一种方法链接可以增强可读性和编写便利性的情况。

null 通常作为带外值返回,表示无法产生任何结果。我认为,当没有结果是正常事件时,这是完全合理的;示例包括在文件末尾从readLine() 返回空值,或者在向Mapget(...) 方法提供不存在的键时返回空值。读取到文件末尾是正常行为(与 IOException 相反,IOException 表示尝试读取时出现异常错误)。同样,查找键并被告知它没有值是正常情况。

在某些情况下,null 的一个很好的替代方案是“null 对象”,它是结果类的完整实例,但对于“nobody's home”情况具有适当的状态和行为。例如,查找不存在的用户 ID 的结果很可能是一个 NullUser 对象,该对象的名称长度为零,并且没有在系统中执行任何操作的权限。

【讨论】:

    【解决方案4】:

    这让我很困惑。 OO 编程语言需要 Smalltalk 的分号:

    tree color: green;
         decor: gaudy;
         practical: false.
    

    对象方法1;方法2。表示“在 obj 上调用 method1,然后在 obj 上调用 method2”。这种对象设置很常见。

    【讨论】:

      猜你喜欢
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-18
      • 2013-04-18
      • 1970-01-01
      • 2016-12-29
      相关资源
      最近更新 更多