6

在 Rails 应用程序中实现Null 对象模式后(也在 RubyTapas 第 112 集中进行了描述),我重构了一些代码,但是有一个语法结构似乎不再起作用。

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

我尝试定义||运算符,但没有奏效。有什么方法可以将这种语法用于空(但“真实”)对象?

4

3 回答 3

6

我曾经写过一篇关于如何在 Ruby 中定义“虚假”对象是不可能的文章,以及为什么试图使 Null Object 虚假的尝试通常会被误导。

基本上,您能做的最好的事情就是使用 , 等提出一个令人困惑的不一致#!对象nil?

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

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

if Actual(obj_that_might_be_null)
  # ...do stuff...
end
于 2013-08-02T13:21:44.307 回答
6

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

你应该有一些调用的目的current_user || redirect_out,这可能是用它做一些事情,或者获取它的一些属性。例如,假设您的代码具有:

(current_user || redirect_out).foo

Whencurrent_user不是 的实例Null::User,您想调用foo它。在这种情况下,你应该做的就是定义Null::User#fooredirect_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 ...将在其上调用例程。

于 2013-08-01T08:48:05.040 回答
4

Ruby 中恰好有两个对象是虚假的:nilfalse. 时期。

不幸的是,您无法定义自己的虚假对象,也无法覆盖布尔运算符(not/除外!)。真的很遗憾:对象可以模拟另一个对象是 OO 的基本支柱之一,但在 Ruby 中无法模拟falseor nil,因此在语言中破坏了 OO 的基本属性之一,否则很不错的OO模型。

于 2013-08-01T10:02:04.783 回答