2

我想find_items在子类中覆盖 Item 的方法UserItem。我应该将该方法添加为protectedorprivate吗?

我现在可以在子类中使用受保护的方法,并且只能在它们所属的类中使用私有方法。

class Item
  def item_ids
    @ids ||= REDIS.zrevrange(key, 0, 100).map(&:to_i)
  end

  def items
    find_items
    item_ids.collect {|id| records.detect {|x| x.id == id}}.compact.map(&:content)
  end

protected
  def items_scope
    Item
  end

  def find_items
    items_scope.find(item_ids)
  end
end

class UserItem < Item
  def initialize(user)
    @user = user
  end
  # should I add it here?
protected
  # or here?
  def items_scope
    Item.where(user_id: @user.id).not_anonymous
  end
end

方法覆盖:

def find_items
  items_scope.where(id: item_ids)
end
4

2 回答 2

2

Ruby 中的语义与您可能习惯的不同。实际上,私有意味着您不能为该方法显式指定接收者,但您也可以从派生类中使用它,只要您不指定接收者即可。因此

class A
  def bar; 42; end
  private :bar
end

class B < A
  def foo; bar; end
end

B.new.foo 工作得很好。因此,Ruby 中的 private 非常接近于其他 OO 语言中的 protected。我什至不记得 Ruby 中的 protected 是什么。它在 Ruby 中很少使用。

在您的示例中,我不会将 private 用于 find_items。我会将其公开或将其转换为 mixin(因为它不使用实例变量)

于 2013-01-14T15:44:19.967 回答
0

如果要保留原始可见性,则必须使新的覆盖​​方法受到保护。如果您不这样做,它将具有公开可见性:

class A
  protected
  def f; 'A'; end
end

class B < A
  def f; 'B'; end
end

class C < A
  protected
  def f; 'C'; end
end

A.new.f  #=> #<NoMethodError: protected method `f' called for #<A:0x007fa754bdd0a0>>
B.new.f  #=> 'B'
C.new.f  #=> #<NoMethodError: protected method `f' called for #<C:0x007fc4f19f2af0>>

最终,这取决于您,但保持原始方法的可见性可能是一个好主意,除非您有特定的理由不这样做。

于 2013-01-14T15:39:59.417 回答