什么是setter方法和虚方法(在Ruby中)之间的区别?

时间:2017-02-12 03:52:01

标签: ruby terminology setter virtual-method

我正在研究Ruby并试图绕过一些词汇。在某个地方,我发现了一个概念,即setter概念也是一种虚拟方法,即它们是同义词。但现在我觉得我错了。而且我想知道这些与工厂方法有什么关系。帮助

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

  

在面向对象的编程中,在诸如C ++之类的语言中,是虚拟的   function或virtual方法是一个可继承和可覆盖的函数   或促进动态调度的方法。

自去年六月以来,我一直在努力学习Ruby,我不知道这意味着什么。

我对setter方法有一些更好的概念。我一直在想它只是设置实例变量值的任何方法。所以attr_writer :foo是一个setter方法,也许是一个改变foo值的类外部的方法也是一个setter方法。是吗?

但那不是什么"虚拟方法"意思是,是吗?所以基本上,我正在寻找差异的解释,我找不到任何(或者,我不能理解)。

所谓的"工厂方法&#34>也是如此。可以被描述为从类外部(即定义类的代码)创建特定类型的对象(由setter方法集合指定)的方法吗?

3 个答案:

答案 0 :(得分:5)

虚拟方法

方法,在类上定义,并在其子类上重新定义,以便调度与接收器的类型相关。例如:

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"

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

Setter方法

首先,attr_writer绝不是设定者。它是动态生成setter 助手。因此,setter本身就是一个设置[变量]的方法。相反的是吸气剂。

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

工厂方法

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

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 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的非常有价值的评论。

答案 1 :(得分:5)

  

在某个地方,我接受了一个概念,即setter概念也是一种虚拟方法,即它们是同义词。

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

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

  

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

     
    

在面向对象的编程中,在诸如C ++之类的语言中,是虚拟的     function或virtual方法是一个可继承和可覆盖的函数     或促进动态调度的方法。

  

这个术语在Ruby中没有意义,因为在Ruby中,所有方法都是虚拟的,因此不需要区分虚拟方法和非虚方法。

在OOP中,术语&#34;虚拟&#34;适用于语言 - &#34;事物&#34;动态调度(即在运行时)并可以重写。

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会返回字符串'Bar',即使在to_s中定义了Foo并只是调用foo。但是,即使在to_s中定义Foo,它也不会调用Foo&#39; foo,而是调用Bar&#39} foo,因为相关对象具有类BarBar已经重写 {/ 1}}的定义,并且调用动态调度到当前对象所具有的任何类。

艾伦凯,他创造了这个术语&#34;面向对象&#34;使用消息传递比喻,恕我直言使这样的事情更容易理解:对象通过发送消息相互通信。它的工作原理就像在现实世界中向某人发送消息时:你无法知道接收者对消息做了什么,所有你能观察到的就是你得到的回应。当你向某人发送消息时,他们会根据自己的知识解释消息中的请求。

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

  1. 您发送消息&#34;将自己转换为字符串&#34;给朋友。
  2. 你的朋友不知道这意味着什么,所以他问他的上级,他告诉他,这意味着&#34;给自己发信息&#39; foo&#39;&#34;。 / LI>
  3. 你的朋友给自己发了一条消息&#34; foo&#34;。
  4. 你的朋友有自己的想法&#34; foo&#34;意思是,所以他不需要查阅。
  5. 其他语言有其他虚拟&#34;事物&#34;,例如Newspeak有虚拟超类。

    所以,如果我有这个:

    foo
      

    我对setter方法有一些更好的概念。我一直在想,这只是设置实例变量值的任何方法。

    是和否。

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

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

    更一般地说,在Ruby中,setter方法是一个名称以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 结尾的方法。

      

    所以=是一个setter方法,

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

      

    也许改变attr_writer :foo值的类外部方法也可能是一个setter方法。是吗?

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

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

      

    但那不是什么&#34;虚拟方法&#34;意思是,是吗?所以基本上,我正在寻找差异的解释,我找不到任何(或者,我不能理解)。

    由于这两个概念是完全正交的,因此谈论它们之间的差异并没有多大意义;他们彼此之间没有任何关系。

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

    特别是在Ruby中,所有方法都是虚拟的,因此所有的setter方法都是虚拟的(因为所有的setter方法都是方法),但那就是它。

      

    所谓的&#34;工厂方法&#34>也是如此。可以被描述为从类外部(即定义类的代码)创建特定类型的对象(由setter方法集合指定)的方法吗?

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

    是的,创建对象的方法是sometimes called "Factory Method"。在Ruby中,使用最广泛的工厂方法是foowhich looks something like this

    new

    实际上,class Class def new(*args, &block) obj = allocate obj.initialize(*args, &block) return obj end end 是一种私有方法,因此我们需要使用反射来规避访问保护,但这并没有改变方法的要点:

    initialize

答案 2 :(得分:1)

Ruby中的所有方法都是虚拟的。&#34;

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

你的直觉是对的,一种工厂方法&#34;必须调用setter方法或将初始化委托给实例方法,因为实例变量在Ruby中是严格私有的。

实际上,new是一个这样的工厂方法,它将初始化委托给名为initialize的实例方法。它在本机代码中实现,并且相当于

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