让一个NullObject在Ruby中评估为falsy

时间:2013-08-01 08:33:18

标签: ruby design-patterns

在Rails应用程序中实现Null Object Pattern之后(也在RubyTapas第112集中描述)我重构了一些代码,但是有一种似乎不再有用的语法结构。

我曾经写过像current_user || redirect_out这样的语句,如果设置了current_user,它会返回它,如果它是nil,它会重定向,但现在current_user可能是一个实例Null::User并因此“truthy”,该片段永远不会重定向。

我尝试定义||运算符,但没有用。有没有什么方法可以使用null(但“truthy”)对象?

3 个答案:

答案 0 :(得分:6)

我认为你只有一半采用了这种模式,并没有正确地采用它的精神。我的理解是,模式的目的是避免||

你应该有一些调用current_user || redirect_out的目的,这可能是用它做某事,或者得到它的一些属性。例如,假设您的代码包含:

(current_user || redirect_out).foo

current_user不是Null::User的实例时,您想在其上调用foo。在这种情况下,您应该做的是将Null::User#foo定义为redirect_out(可能会在其他类上执行更多操作,如foo。)

class Null::User
  def foo; redirect_out ... end
end

代替(current_user || redirect_out).foo,你应该做

current_user.foo

current_user不是Null::User个实例时,它会调用foo。如果是这样的实例,则会在其上调用redirect_out ...例程。

答案 1 :(得分:6)

我曾经写过an article关于如何在Ruby中定义“虚假”对象的问题,以及为什么尝试使Null对象伪造通常是错误的。

基本上,您可以做的最好的事情是使用#!nil?等提出一个容易混淆的不一致对象。

正如其他人所指出的那样,通常当你想让Null对象“虚假”时,这是因为你没有充分利用多态性。 Null对象的要点是避免类型检查,并且以NilClass语句的形式检查if与任何其他语句一样都是类型检查。

那就是说,有时这是不可避免的。这就是为什么在我的Naught库中我生成一个名为Actual()的辅助转换函数(在其他几个转换中)。 Actual()将Null对象转换回nil值,但仅保留所有其他对象。因此,对于需要打开对象真实性的情况,您可以这样做:

if Actual(obj_that_might_be_null)
  # ...do stuff...
end

答案 2 :(得分:3)

Ruby中只有两个伪造的对象:nilfalse。周期。

不幸的是,无法定义自己的假对象,也无法覆盖布尔运算符(not / !除外)。实在是太遗憾了:它是OO的基本支柱之一,一个对象可以模拟另一个对象,但在Ruby中,无法模拟falsenil,因此打破其中一个OO的基本属性在一种语言中具有非常好的OO模型。