English 中文(简体)
运用返回语句极好地发挥作用!
原标题:
  • 时间:2008-12-26 10:38:38
  •  标签:

当我写有返回值的方法时,我通常会尝试设置这样一种情况:在调用方法时永远不会出现必须返回一些默认值的情况。当我开始写方法时,我经常会写一些做一些事情并将其返回,或者如果它们没有做任何事情,则返回null的方法。但我讨厌在代码中到处使用丑陋的if(!null)语句。

我正在阅读《Ruby 入门指南》,这是我多年前读过的一本书,它是由实用主义程序员撰写的。我注意到他们通常在不需要返回任何内容时返回 self(Ruby 的 this)。他们说,这样做是为了能够链式调用方法,例如使用返回设置其属性的对象的设置器的示例。

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

起初,我认为这种东西很吸引人。有几次我很高兴能够链接方法调用,比如Player.getHand().getSize(),但这有点不同,因为方法调用的对象会随着步骤的改变而改变。

Stack Overflow对于返回值有什么看法?当你想到返回值时,是否有任何模式或习惯用语让你感到温暖?有什么好的方法可以避免沮丧并增加美感?

最佳回答

依我的謙卑看法,有三種回報情況你應該考慮:

Object property manipulation

第一是操作对象属性。当操作对象时,您所描述的模式经常被使用。非常典型的情况是将其与工厂一起使用。考虑这个假设的创建调用:

// 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的方法一起使用。

Evaluating object properties

第二种可能是当一个方法在对象上评估某些东西。例如,考虑方法car.getCurrentSpeed(),它可以被解释为对一个对象的消息,请求当前速度并返回。它只会返回值,不太复杂。 :)

Make object do this or that

第三种可能是当一个方法执行操作,在返回某种值时指示调用者的意图实现得如何 - 但是设计这样的方法可能会很困难:

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

这是在设计方法时可以看到的困难。成功或失败时是否应返回0?如果汽车只有5档,无法设置齿轮,那么-1呢?这是否意味着当前齿轮现在也在-1位置?该方法可以返回更改的齿轮,这意味着您必须将传递给方法的参数与返回代码进行比较。那将起作用。另一方面,您可以只返回失败或真或假或真。其中一个要使用可以通过估计这些方法调用是否更有可能失败或成功来决定。

在我谦虚的观点中,有一种更好地表达这种返回值语义的方法,那就是给它们一个语义描述。未来与你的对象进行交互的开发人员会很感激你,因为他们不必查阅你的方法的注释或文档。

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

GearChangeResult changeGear (int gear);
};

这样一来,任何查看你的代码的程序员都会非常明显地知道返回值的含义(考虑:if(gears.changeGear(20) == GearSystem::GearChangeSuccess)——比上面的例子更清楚地说明了含义)。

Antipattern: Failures as return codes.

第四个可能的返回值我实际上忽略了,因为我认为它并不存在:当你的程序有错误时,例如逻辑错误或需处理的故障 - 你可以理论上返回一个指示这种情况的值。但如今,这并不经常发生(或者不应该),因为有对应的异常处理机制。

问题回答

我不同意方法永远不应返回null的说法。最明显的例子来自系统编程。例如,如果有人要求打开一个文件,如果打开失败,你只能给他们一个null。没有其他合理的选择。还有其他一些情况,null也是合适的,比如在链表的最后一个节点上调用getNextNode(node)方法。所以我想这些情况的共同点是null代表"没有对象"(要么没有文件句柄,要么没有链表节点),这是有意义的。

在其他情况下,该方法永远不应失败,并且有一个适当的异常处理机制。然后,我认为像您的示例一样可以使用方法链,效果很好。我觉得有点有趣的是,您似乎认为这是“实用程序员”的创新。事实上,它可以追溯到Lisp甚至更早的时期。

返回this也可用于“构建器模式”,这是另一种方法链可以提高可读性和编写便利性的案例。

null经常作为一种超出范围的值返回,以指示无法产生任何结果。我认为,当没有结果是正常事件时,这是完全合理的。例如,从文件末尾的readLine()返回null,或在Mapget(...)方法中提供不存在的键时返回null。读取到文件末尾是正常行为(与IOException相反,后者表示在尝试读取时出现异常)。同样地,查找一个键并被告知它没有值是一个正常的情况。

一些情况下,与 NULL 相比的好选择是一个“null 对象”,它是结果类的一个完整实例,但它具有适合“无人在家”情况的适当状态和行为。例如,查找不存在的用户 ID 的结果可能是一个 NullUser 对象,它具有零长度的名称并且没有在系统中执行任何操作的权限。

这对我来说很困惑。面向对象编程语言需要Smalltalk的分号:

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

obj.method1(); obj.method2(); 意味着“在 obj 上调用 method1,然后在 obj 上调用 method2”。 这种对象设置非常常见。





相关问题
热门标签