【问题标题】:DelegateClass vs Class Inheritance in RubyRuby 中的 DelegateClass 与类继承
【发布时间】:2016-12-13 00:50:11
【问题描述】:
有人可以提供一些关于何时通过DelegateClass(例如Seller < DelegateClass(Person))使用委托以及何时在ruby 中使用类继承(例如Seller < Person)的见解吗?
class Seller < DelegateClass(Person)
def sales
...
end
end
class Seller < Person
def sales
...
end
end
当我在 Github 上查看 Ruby on Rails 源代码时,我发现了很多 uses of DelegateClass。
【问题讨论】:
标签:
ruby
inheritance
delegation
【解决方案1】:
有几个不同之处可以帮助您深入了解使用哪种方法。
1) 您可以安全地委托给原语(例如字符串),但不能始终安全地从它们继承
如果您在 Hash 或 String 或 Fixnum 之上构建,则使用 DelegateClass(或其他委托人)会更安全。有关原因的更多信息,Steve Klabnik's cautioning 是一个不错的起点)。
2) DelegateClass 可以轻松地将更通用的对象“转换”为更具体的对象
这使得接受通用对象的实例并使其以特定于您的实现的方式运行变得更容易:
class Message < DelegateClass(String)
def print
upcase
end
end
# […]
def log(message)
message = Message.new(message) unless message.is_a?(Message)
end
3) 一个陷阱:DelegateClass 子类期望委托类的实例作为new 的参数
这会使您将交给库代码的类“子类化”变得很棘手。例如,这是一种相当普遍的做法,在 DelegateClass 中无法立即使用:
class MyLogger < DelegateClass(ActiveSupport::Logger); end
Foo::ThirdParty::Library.configure do |c|
c.logger = MyLogger # no good
end
这是行不通的,因为我们的库希望表现得像大多数记录器并在没有参数的情况下实例化。这可以通过定义initialize 并创建ActiveSupport::Logger 的实例来解决,但在这种情况下可能不是正确的解决方案。
【解决方案2】:
委托根据上下文对Person 的不同行为进行建模。例如同一个人可能是一种情况下的卖方,也可能是不同情况下的买方。继承更加严格:Bear 和Tiger 继承自Animal,但Animal 的实例永远不需要有时表现得像Bear,有时表现得像Tiger。 Animal 的后代实例是其中之一。