2

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

我正在阅读我很多个月前阅读的实用程序员的 ruby​​ 重新指南,我注意到他们经常返回self(ruby's this),而他们通常不会返回任何东西。他们说,这是为了能够链接方法调用,就像在这个例子中使用返回他们设置属性的对象的 setter 一样。

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

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

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

4

4 回答 4

5

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

对象属性操作

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

// 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 表示失败。可以通过估计您是否希望这些方法调用失败或成功来决定使用哪一个。

在我看来,有一种方法可以更好地表达这些返回值的语义,通过给它们一个语义描述。未来与您的对象交互的开发人员会喜欢您,因为您不必为您的方法查找注释或文档:

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

GearChangeResult changeGear (int gear);
};

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

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

我实际上省略了返回值的第四种可能性,因为在我看来它不是任何:当您的程序中出现错误时,例如逻辑错误或需要处理的故障 - 您理论上可以返回一个值指示所以。但是今天,这不再经常(或不应该)这样做,因为为此,有例外。

于 2008-12-26T11:22:35.323 回答
1

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

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

于 2008-12-26T11:19:56.530 回答
1

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

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

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

于 2008-12-26T17:12:19.077 回答
0

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

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

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

于 2008-12-26T11:22:21.063 回答