setter 方法和虚拟方法(在 Ruby 中)有什么区别?

What's the difference between a setter method and a virtual method (in Ruby)?

我正在学习 Ruby 并试图掌握一些词汇。在某个地方,我发现 setter 概念也是一种虚拟方法,即它们是同义词。但现在我想我错了。我想知道这些与工厂方法有什么关系。有帮助吗?

维基百科关于虚拟方法的说法:

In object-oriented programming, in languages such as C++, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated.

我从去年 6 月开始就一直在努力学习 Ruby,但我不知道那意味着什么。

我确实对 setter 方法是什么有了更好的理解。我一直在想,它只是设置实例变量值的任何方法。所以 attr_writer :foo 是一个 setter 方法,也许 class 外部的方法改变 foo 的值也是一个 setter 方法。是吗?

但这不是 "virtual method" 的意思,是吗?所以基本上,我正在寻找差异的解释,但我找不到任何(或者,不是我能理解的)。

情况也是如此,不是吗,所谓的 "factory method" 可以描述为创建特定类型对象的方法,由 setter 的集合指定方法,来自 class 之外(即定义 class 的代码)?

虚方法

方法,在class上定义,并在它的子class上重新定义,因此调度与接收者的类型有关。示例:

class A; def m; puts "A"; end; end
class B < A; def m; puts "B"; end; end
class C < A; end
[A, B, C].map(&:new).each(&:m)
#⇒ "A"
#  "B"
#  "A"

也就是说,无论一个人是否有一个对象,只要她确定,她就不必费心进行类型检查,该对象是任何 class 的实例,派生自 A。如果此特定 class 上未定义该方法,则会查找整个继承树,直到找到该方法定义并调用该找到的方法。

Setter方法

首先,attr_writer绝不是setter。它是动态生成 setter 的 助手。根据它的名字,setter 本身是一种方法,它确实设置了 [a variable]。相反的是 getter.

class A; def set(v); @v = v; end; def get; @v; end; end
instance = A.new
instance.set(42)
instance.get
#⇒ 42

工厂方法

它[通常]产生实例。工厂可以在 class 定义中声明(广泛用于单例等):

class A
  def m; puts "A"; end
  # note A.produce, to make it a class method
  def A.produce; A.new; end
  # or self.produce, to make it a class method
  # def self.produce; A.new; end # ⇐ the same as above
end
A.produce
#⇒ #<A:××××××>
A.produce.m
#⇒ "A"

或在 class 定义之外:

class A; def m; puts "A"; end; end
def produceA; A.new; end
# or from withing other class
class B; def produceA; A.new; end; end

produceA.m
#⇒ 42
B.new.produceA.m
#⇒ 42

另请查看下面 Cary Swoveland 对 attr_writer 的非常宝贵的评论。

Ruby中的所有方法都是"virtual."

我使用引号是因为 Ruby 中没有这样的区别。该维基百科文章中讨论的概念仅对 C++ 有意义,不适用于 Ruby。例如,Ruby 也没有构造函数。

您的直觉是正确的,"factory method" 必须调用 setter 方法或将初始化委托给实例方法,因为实例变量在 Ruby 中是严格私有的。

事实上,new就是这样一种工厂方法,它将初始化委托给名为initialize的实例方法。它以本机代码实现,相当于

class Object 
  def self.new
    object = allocate
    object.initialize # delegate initialization to an instance method
    return object
  end
end

Somewhere I picked up the notion that a setter notion is also a virtual method, i.e., they're synonyms.

这是一个逻辑错误:狗也是哺乳动物,但这并不意味着它们是同义词。

同样,在Ruby中,setter方法也是虚方法(因为在Ruby中所有方法都是虚方法),但是它们不是同义词。由于Ruby中只有虚方法,你也可以说:setter方法也是方法。现在,很明显这并不一定意味着方法也是 setter 方法,对吧?

Wikipedia says this about virtual methods:

In object-oriented programming, in languages such as C++, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated.

该术语在Ruby中没有意义,因为在Ruby中,所有方法都是虚拟的,因此无需区分虚拟方法和non-virtual方法。

在一般的 OOP 中,术语 "virtual" 适用于动态调度(即在运行时)并且可以被覆盖的语言-"things"。

class Foo
  def to_s
    foo
  end

  def foo
    'Foo'
  end
end

class Bar < Foo
  def foo
    'Bar'
  end
end

Bar.new.to_s
#=> 'Bar'

如您所见,Bar.new.to_s returns 字符串 'Bar',即使 to_s 是在 Foo 中定义的并且只是调用 foo.但是,即使 to_s 定义在 Foo 中,它也不会调用 Foofoo,而是调用 Barfoo,因为有问题的对象有 class BarBar 覆盖 foo 的定义,调用被动态 分派给 [=134] =] 当前对象有.

创造术语 "object oriented" 的 Alan Kay 使用了一个消息隐喻,恕我直言,这样的事情更容易理解:对象通过发送消息相互通信。它的工作原理就像 在现实世界中向某人发送消息一样:你无法知道接收者对消息做了什么,你只能观察到你得到的响应。而当你给别人发消息时,他们会根据自己的知识解读消息中的请求。

所以,如果你想象一下你和朋友之间的这种交流:

  1. 您将消息 "convert yourself to a string" 发送给朋友。
  2. 你的朋友不知道那是什么意思,所以他问他的上级,他告诉他,这意味着 "send yourself the message 'foo'"。
  3. 您的朋友向自己发送消息 "foo"。
  4. 你的朋友对"foo"的含义有自己的理解,所以他不需要查找。

其他语言有其他虚拟"things",例如新话有虚超classes.

所以,如果我有这个:

class Foo < Array
  # … stuff
end

class Bar
  def Array
    return SomeClassLikeArray
  end

  def bar
    Foo.new
  end
end

Bar.new.bar
# this will be a `Foo` which has `SomeClassLikeArray` as its superclass

I do have a little better notion of what setter methods are. I've been thinking that it is just any method that sets the value of an instance variable.

是也不是。

似乎是设置实例变量的方法。您实际上并不知道该方法的作用。 (记住消息传递的比喻:你只能观察你朋友的反应,你不知道你的朋友实际上对消息做了什么!)

例如,在 web 框架中,setter 方法可能实际上写入数据库而不是设置实例变量。

更技术性的说明,一般来说,在Ruby中,setter方法是名称以=.

结尾的方法

So attr_writer :foo is a setter method,

不,那不是 setter 方法。 It creates a setter method named foo=.

and maybe a method external to a class that changes the value of foo would also be a setter method. Is that right?

这不是我们通常所说的setter方法。这在 Ruby 中也是不可能的,因为只有对象本身可以访问其实例变量。

即使在允许它的语言中,它也是糟糕的设计:对象应该 do 东西,而不是 store 东西。它是关于行为。您应该告诉 对象执行操作

But that's not what "virtual method" means, is it? So basically, I'm looking for an explanation of the differences and I can't find any (or, not that I can understand).

谈论它们的区别并没有什么意义,因为这两个概念是完全正交的;他们彼此没有任何关系。

虚方法是一种可以被覆盖的方法。 setter 方法是一种设置东西的方法。你可以有一个可以被覆盖的setter方法,一个不能被覆盖的setter方法,一个non-setter 方法可以被覆盖,一个 non-setter 方法不能被覆盖。

具体在Ruby中,所有方法都是虚的,所以所有setter方法都是虚的(因为所有setter方法都是方法),仅此而已。

It's also the case, isn't it, that a so-called "factory method" could be described as method to create an object of a particular type, as specified by a collection of setter methods, from outside of the class (i.e., the code defining the class)?

所以,有一个Design Pattern called Factory Method,但是你说的是创建对象的方法的更一般的概念。

是的,一个创建对象的方法是sometimes called "Factory Method". In Ruby, the most widely-used factory method is new, which looks something like this:

class Class
  def new(*args, &block)
    obj = allocate
    obj.initialize(*args, &block)
    return obj
  end
end

实际上,initialize是一个私有方法,所以我们需要使用反射来绕过访问保护,但这并没有改变方法的主旨:

class Class
  def new(*args, &block)
    obj = allocate
    obj.__send__(:initialize, *args, &block)
    return obj
  end
end