`
sizhefang
  • 浏览: 227040 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Ruby 单件类

    博客分类:
  • ruby
阅读更多
   非常感谢javaeye上的各位大牛,给我们这些小虾们总结了这么多入门的文档。把potian同学总结的作为收藏。

单件类(Singleton Class)
在Ruby中,定义一个类可以有两种方法:


class [ scope:: ] classname [ < superexpr ]
   body
end

class << obj
   body
end
这两种方法的存在是一个事实造成的,Ruby不但可以定义适合普通的类,还可以为某一个具体的对象定义它特定的类。譬如,我们定义了一个普通的类A.

对象和类

class A
    def who
        puts “I’m a instance of class A”
    end
end
现在你可以用A创建出很多对象,例如:


a1 = A.new
a2 = A.new
a3 = A.new
由于a1,a2,a3都是A的实例,因此它们的行为都是一样的。譬如,它们都能够接收who这个消息:


a1.who        # I’m a instance of class A
a2.who        # I’m a instance of class A
a3.who        # I’m a instance of class A
我们也可以证明所有对象的类都是A


a1.class  #A
a2.class  #A
a3.class  #A
当然,对某一个实例不存在的方法。另一个实例也不可能去响应。



a1.special #NoMethodError: undefined method `special' for #<A:0x356f40>
a2.special #NoMethodError: undefined method `special' for #<A:0x35369c>
a3.special #NoMethodError: undefined method `special' for #<A:0x34de04>
深入Ruby的源代码,你可以看到,所有的Ruby对象结构上都有一个属性,叫做klass,说明了它所属的类:



图1-对象和它们的类

a1,a2,a3对象的klass属性指向同一个结构class A,而class A有一个属性m_tbl,实际上是一个Hash表,里面保存了这个类的所有实例方法,除了其它方法之外,我们刚刚定义的who也赫然在列,这个方法表叫做实例方法表。

当代码调用某一个具体对象的方法时,Ruby首先在它的class,也就是A的实例方法表中寻找,如果找到了,那么就调用这个方法。不然,通过一系列的搜索还没有找到这个方法,就抛出未定义方法错误(我们暂时不考虑method_missing)。因此,很容易理解,对a1,a2存在的方法,对a3这个对象当然也存在,而对a1,a2不存在的方法,对a3当然也不存在。

超类
前面我说要经过一系列搜索,这个搜索就是超类。类是可以继承的,假设A是从B中继承下来的,那么A的对象实例就获得了B的实例方法。


class B
    def where
        puts "Here is class B"
    end
end
class A<B
  def who
    puts "I’m a instance of class A"
  end
end

a1 = A.new
a2 = A.new
a3 = A.new

a1.who              # I’m a instance of class A
a2.who            # I’m a instance of class A
a3.who            # I’m a instance of class A

a1.where        # Here is class B
a2.where        # Here is class B
a3.where        # Here is class B
在超类加入以后我们的对象和类关系增加了一层:



图2 对象-类—超类

在搜索一个对象方法的过程中,首先搜索这个对象本身类的实例方法表,如果没有找到,那么将搜索这个类的超类的实例方法表,一直向上搜索,直到超类为空(Object的超类为空).

在上面的例子中,当我们调用a3.where方法时,Ruby 首先搜索class A的实例方法表,发现其中没有where方法,因此它沿着类的超类向上,得到class A的超类class B,在它的方法表中找到了where.

单件类
但是,Ruby可以可以让我们定义只对a3存在的方法,例如


def a3.special
    puts “I’m so special”
end

a3.special  #I’m so special
显然,a3现在已经有了special方法,但是,如果我们去调用a1和a2的special方法,那么结果还是一样的:


a2.special  # undefined method `special' for #<A:0x1e41ac> (NoMethodError)
a1.special  # undefined method `special' for #<A:0x1e41e8> (NoMethodError)
但是,如果我们继续调用a3.who方法,好好在那里

a3.who        => I’m a instance of class A
Ruby设计者是怎样解决这个问题的呢?回忆我们前面讲到的实例方法的搜索路径,一个巧妙的设计诞生了:
 
我们从图中的虚线可以看到,原先a3和a1、a2一样,它的klass都指向class A,但是现在a3的klass指向一个新的sclass 而sclass的超类是原先的sclass,所有为a3对象单独定义的方法都放在这个sclass的实例方法表中。因为它只为某一个对象所用,所以我们把这个sclass称为单件类。

巧妙之处何在?巧妙在于,用老规则解决新问题。旧的搜索规则规定,对象的方法首先搜索这个对象所属类的方法表,如果找不到则搜索超类,直到搜索成功或者没有超类为止。这个设计完全遵照这一规则。

上图中,a1,a2没有任何变化,所以它们的行为依旧。但是对于对象a3而言,由于它的类指向了一个新单件类sclass,因此,当程序调用a3.special方法,ruby很快就从这个单件类中搜索到了special方法。而如果调用的是who或者where,由于无法在单件类中找到这些方法,那么就会沿着超类而上进行搜索,而它之上所有的结构都没有变化。因此,原先的所有方法依旧可用。更重要的是,不管A以及它的超类如何变化,所有这些变化都能够在a3这个对象中得到体现。

现在我们可以下一个结论,什么是单件方法,单件方法是在单件类中定义的方法?什么是单件类,用来存储单件方法的类就是单件类。它们都是为某一个具体的对象服务的。

从图中我们可以看到a3.klass指向的是这个单件类,那么a3.class的结果是什么呢?

    a3.class #A
很奇怪,依然是A。 Ruby在给出一个对象的class时候,只会给出它的“real_class”-不是单件类的类。从另外一个角度考虑,由于这个单件类没有任何名字,同时也不可能被实例化,确实并不需要明确地以.class的方式获取。 但是,很多时候我们还是需要在这个单件类内部进行操作。举个简单的例子,假设我想为a3定义很多方法,如果按照前面的方法,那么只能一个一个定义:

    def a3.singleton_method1
    end
    def a3. singleton_method2
    end
    def a3. singleton_method3
    end
    def a3. singleton_method4
    end
    …….
    def a3. singleton_methodn
    end
这样做非常繁复,而且无法给出一个统一的概念模型,因此Ruby提供了另外一种方法,能够让你“打开”单件类,并在其中操作。这就是我们在最开始提到的第2种定义类的方法:

class << obj
…..
end
obj是一个具体的对象实例,class << 代表它的单件类。
[img][/img]
分享到:
评论
1 楼 allwefantasy 2009-05-27  
讲解的很细致。potian写的 帖子 “单件类”很不错 可惜不怎么适合我这种感接触ruby的人。

相关推荐

    详解Ruby中的单件方法和单件类

    ### 详解Ruby中的单件方法和单件类 在Ruby编程语言中,单件方法(Singleton Method)和单件类(Singleton Class)是两个非常重要的概念。这些特性为Ruby提供了强大的灵活性,允许开发者针对特定的对象定义唯一的...

    Ruby 方法、类

    在Ruby中,方法和类是构建程序的基本元素,它们是实现代码重用和组织的关键概念。 ### 方法(Methods) 方法在Ruby中是可重复使用的代码块,它们接受参数,执行特定任务,并可能返回值。方法定义使用`def`关键字...

    类变量、全局变量、实例变量, 多态、为什么ruby、ruby编码规范

    本文将深入探讨Ruby语言中的类变量、全局变量、实例变量,以及多态的概念,并结合Ruby编码规范来阐述如何有效地编写代码。 一、类变量 类变量在Ruby中以`@@`前缀表示,它们是属于类或模块的共享变量,不会被类的...

    Ruby Ruby Ruby Ruby Ruby Ruby

    Ruby Ruby Ruby Ruby Ruby Ruby

    Ruby-Refrigerator冻结所有核心ruby类

    然而,这种灵活性也意味着在某些情况下,程序可能会无意中修改核心的Ruby类或模块,这可能导致不可预测的行为,尤其是在生产环境中。为了防止这种情况,开发者可以使用特定的工具,如"Ruby-Refrigerator"。 "Ruby-...

    Ruby-rubybuild编译和安装Ruby

    对于Unix或类Unix系统(如Linux和macOS),可以在终端执行以下命令: ```bash $ git clone https://github.com/rbenv/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' &gt;&gt; ~/.bashrc $ echo '...

    ruby DBI ruby DBI ruby DBI

    ruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ...

    Ruby编程Ruby Programming

    - **动态性**:Ruby支持运行时修改代码结构,允许开发者在程序运行过程中改变类和方法的行为。 - **元编程能力**:Ruby提供了一种称为元编程的技术,使得程序可以自我修改和自我扩展。 ### 二、Ruby编程基础 #### ...

    Ruby-MongoMapper针对Mongo的一个Ruby对象映射器

    1. **模型定义**:你可以定义一个Ruby类并继承自`MongoMapper::Document`,然后使用`key`方法声明属性,这类似于ActiveRecord中的`attr_accessor`。例如: ```ruby class User include MongoMapper::Document ...

    Ruby-Ruby的面向对象的枚举

    Ruby的枚举通常指的是枚举类(Enum Class),这是一种自定义枚举类型的方法,允许我们创建具有特定行为的枚举。在本篇文章中,我们将深入探讨Ruby如何实现面向对象的枚举以及它在实际开发中的应用。 首先,让我们...

    Ruby完全自学手册

    2. 面向对象编程:类与对象、继承、多态、封装、模块等。 3. 高级特性:块(Block)、迭代器(Iterator)、元编程、反射等。 4. 标准库的使用:文件操作、网络编程、正则表达式处理等。 5. Ruby on Rails框架的学习...

    ruby2ruby.zip

    ruby2ruby 提供一些用来根据 RubyParser 兼容的 Sexps 轻松生成纯 Ruby 代码的方法。可在 Ruby 中轻松实现动态语言处理。 标签:ruby2ruby

    Ruby完全自学手册 下

    《Ruby完全自学手册》是一本完全覆盖Ruby和Ruby on Rails的完全自学手册。《Ruby完全自学手册》的特色是由浅入深、循序渐进,注重理论和实践的结合。虽然定位为入门手册,但是依然涉及许多高级技术和应用,覆盖到的...

    Ruby-rubyinstall安装RubyJRubyRubiniusMagLevorMRuby

    Ruby是一种强大的、面向对象的脚本语言,广泛用于Web开发、服务器端编程和各种应用程序。在Ruby的世界里,管理不同的Ruby实现(如MRI、JRuby、Rubinius、MagLev和MRuby)是非常重要的,这有助于开发者根据项目需求...

    src-oepkgs/ruby-ruby2ruby

    src-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2rubysrc-oepkgs/ruby-ruby2...

    ruby(前途大好的ruby+rains)

    8. **标准库丰富**:Ruby的标准库包含了大量实用的模块和类,如文件操作、网络通信、XML解析等,为开发者提供了便利。 提到Ruby,就不得不提Rails框架。Ruby on Rails(简称Rails)是由David Heinemeier Hansson...

    ruby源代码 ruby源代码 ruby源代码 ruby源代码2

    ruby源代码 ruby源代码 ruby源代码 ruby源代码2

    Ruby元编程 源代码 Metaprogramming Ruby source code

    2. **类和模块的开放性**:Ruby的类和模块在运行时可以被修改,这意味着你可以在程序的任何时刻向它们添加新的方法或属性。`class 语法常用于在类的上下文中定义方法。 3. **消息发送**:`send`或`__send__`方法...

Global site tag (gtag.js) - Google Analytics