单例类

单例方法是属于单个对象的方法。另一方面,单例类(singleton class)则是定义单个对象的类。感到困惑?我也是。那么让我们仔细看看这些令人讨厌的东西…

假设你创建了几十个对象,每个对象都是 Object 类的一个实例。自然的,它们都可以访问 Object 类的常用方法,例如 inspectclass。但是现在你决定只想要一个特殊的对象(为了区别,让我们称之为 ob),它有一个特殊的方法(让我们称之为 blather)。

你不希望为此对象定义一个全新的类,因为你永远不会再创建更多拥有 blather 方法的对象。 所以你特别针对 ob 创建了一个类。

你无需为该类命名。你只需要通过在 class 关键字和对象名之间放置一个 << 符号将它本身附加到 ob 上。然后你可以以通常的方式在类中添加代码:

singleton_class.rb
  1. ob = Object.new
  2. # singleton class
  3. class << ob
  4. def blather( aStr )
  5. puts("blather, blather #{aStr}")
  6. end
  7. end

现在 ob,并且只有 ob,不仅拥有 Object 类的所有常用方法;它也拥有了(这里只有 blather 方法,但原则上可以有更多)自己特殊的匿名类(anonymous class)中的方法:

  1. ob.blather( "weeble" ) #=> “blather, blather weeble”

如果你一直在密切关注,你可能已经注意到单例类(singleton class)似乎正在做一些与单例方法(singleton method)类似的事情。使用单例类,我可以创建一个对象,然后在匿名类中打包添加额外的方法。使用单例方法,我可以创建一个对象,然后逐个添加方法:

  1. ob2 = Object.new
  2. def ob2.blather( aStr ) # <= this is a singleton method
  3. puts( "grippity, grippity #{aStr}" )
  4. end
  5. ob2.blather( "ping!" ) #=> grippity, grippity ping!
singleton_class2.rb

同样地,我可以重写 “star prize” 程序。在之前的版本中一个名为 starprize 的对象添加了一个单例方法,congratulate。我也可以很容易地创建一个包含 congratulate 方法的单例类:

  1. starprize = MyClass.new( "Star Prize" )
  2. class << starprize
  3. def congratulate
  4. puts( "You've won a fabulous holiday in Grimsby!" )
  5. end
  6. end

事实上,相似性不仅限于表面。上面代码的最终结果是 congratulate 成为 starprize 的单例方法,并且我已经使用此测试进行了验证:

  1. if item.singleton_methods.include?("congratulate")

单例方法,单例类 - 有什么区别?

简单的说:区别不大。这两种语法提供了向特定对象添加方法,而不是将这些方法构建到其定义类中的不同实现方式。