Can someone please provide some insight as to when to use delegation via DelegateClass
(e.g. Seller < DelegateClass(Person)
) and when to use class inheritance (e.g. Seller < Person
) in ruby?
有人可以提供一些见解,了解何时通过DelegateClass使用委托(例如卖方
class Seller < DelegateClass(Person)
def sales
...
end
end
class Seller < Person
def sales
...
end
end
When I was looking over the Ruby on Rails source on Github I found quite a few uses of DelegateClass
.
当我在Github上查看Ruby on Rails源代码时,我发现了DelegateClass的一些用法。
2 个解决方案
#1
5
There are a couple of differences that can help provide insight as to which approach to use.
有一些差异可以帮助提供有关使用哪种方法的见解。
1) You can safely delegate to primitives (e.g. String), but cannot always safely inherit from them
1)您可以安全地委托给基元(例如String),但不能总是安全地从它们继承
If you're building on top of Hash
or String
or Fixnum
, you're safer using DelegateClass
(or another delegator). For more on why, Steve Klabnik's cautioning is a good place to start).
如果你在Hash或String或Fixnum之上构建,那么使用DelegateClass(或其他委托者)会更安全。有关原因的更多信息,Steve Klabnik的警告是一个很好的起点)。
2) DelegateClass makes it easy to “convert” a more general object into a more specific one
2)DelegateClass可以轻松地将更通用的对象“转换”为更具体的对象
This makes it easier to accept an instance of a general object and make it behave in a way that's specific to your implementation:
这样可以更容易地接受一般对象的实例,并使其以特定于您的实现的方式运行:
class Message < DelegateClass(String)
def print
upcase
end
end
# […]
def log(message)
message = Message.new(message) unless message.is_a?(Message)
end
3) A gotcha: DelegateClass
subclasses expect an instance of the delegated class as an argument to new
3)一个问题:DelegateClass子类期望委托类的实例作为new的参数
This can make it tricky to “subclass” classes that you're handing to library code. For example, this is a fairly common practice that won't work out of the box with DelegateClass
:
这可能会使您将要传递给库代码的类“子类化”变得棘手。例如,这是一种相当常见的做法,它不能与DelegateClass一起使用:
class MyLogger < DelegateClass(ActiveSupport::Logger); end
Foo::ThirdParty::Library.configure do |c|
c.logger = MyLogger # no good
end
This doesn't work because our library expects to behave like most loggers and instantiate without arguments. This can be addressed by defining initialize
and creating an instance of ActiveSupport::Logger
, but probably not the right solution in this case.
这不起作用,因为我们的库期望像大多数记录器一样运行并且不带参数进行实例化。这可以通过定义初始化和创建ActiveSupport :: Logger的实例来解决,但在这种情况下可能不是正确的解决方案。
#2
1
delegates model different behaviors of Person
based on the context. e.g. the same person could be a seller in one context or a buyer in a different context. Inheritance is more rigid: a Bear
and Tiger
inherit from Animal
, but an instance of Animal
would never need to sometimes behave like a Bear
and sometimes behave like a Tiger
. An instance of a descendent of Animal
is either one or the other.
代表根据上下文模拟Person的不同行为。例如同一个人可以是一个上下文中的卖方,也可以是不同上下文中的买方。继承更加僵化:熊和老虎继承自动物,但动物的一个实例永远不需要有时像熊一样,有时表现得像老虎。动物后代的一个例子是一个或另一个。
#1
5
There are a couple of differences that can help provide insight as to which approach to use.
有一些差异可以帮助提供有关使用哪种方法的见解。
1) You can safely delegate to primitives (e.g. String), but cannot always safely inherit from them
1)您可以安全地委托给基元(例如String),但不能总是安全地从它们继承
If you're building on top of Hash
or String
or Fixnum
, you're safer using DelegateClass
(or another delegator). For more on why, Steve Klabnik's cautioning is a good place to start).
如果你在Hash或String或Fixnum之上构建,那么使用DelegateClass(或其他委托者)会更安全。有关原因的更多信息,Steve Klabnik的警告是一个很好的起点)。
2) DelegateClass makes it easy to “convert” a more general object into a more specific one
2)DelegateClass可以轻松地将更通用的对象“转换”为更具体的对象
This makes it easier to accept an instance of a general object and make it behave in a way that's specific to your implementation:
这样可以更容易地接受一般对象的实例,并使其以特定于您的实现的方式运行:
class Message < DelegateClass(String)
def print
upcase
end
end
# […]
def log(message)
message = Message.new(message) unless message.is_a?(Message)
end
3) A gotcha: DelegateClass
subclasses expect an instance of the delegated class as an argument to new
3)一个问题:DelegateClass子类期望委托类的实例作为new的参数
This can make it tricky to “subclass” classes that you're handing to library code. For example, this is a fairly common practice that won't work out of the box with DelegateClass
:
这可能会使您将要传递给库代码的类“子类化”变得棘手。例如,这是一种相当常见的做法,它不能与DelegateClass一起使用:
class MyLogger < DelegateClass(ActiveSupport::Logger); end
Foo::ThirdParty::Library.configure do |c|
c.logger = MyLogger # no good
end
This doesn't work because our library expects to behave like most loggers and instantiate without arguments. This can be addressed by defining initialize
and creating an instance of ActiveSupport::Logger
, but probably not the right solution in this case.
这不起作用,因为我们的库期望像大多数记录器一样运行并且不带参数进行实例化。这可以通过定义初始化和创建ActiveSupport :: Logger的实例来解决,但在这种情况下可能不是正确的解决方案。
#2
1
delegates model different behaviors of Person
based on the context. e.g. the same person could be a seller in one context or a buyer in a different context. Inheritance is more rigid: a Bear
and Tiger
inherit from Animal
, but an instance of Animal
would never need to sometimes behave like a Bear
and sometimes behave like a Tiger
. An instance of a descendent of Animal
is either one or the other.
代表根据上下文模拟Person的不同行为。例如同一个人可以是一个上下文中的卖方,也可以是不同上下文中的买方。继承更加僵化:熊和老虎继承自动物,但动物的一个实例永远不需要有时像熊一样,有时表现得像老虎。动物后代的一个例子是一个或另一个。