Ruby学习之深入类
在讨论对象模型时,对类做了初步了解,关于类本身,还有许多知识需要学习。
类定义
Ruby中,可以用class关键字或者Class.new方法来定义一个类,在Ruby中,类定义的同时就是在运行代码,类和方法、块一样,会返回最后一条语句的值,由于类也是一个对象(Class的实例),所以在类定义操作时,类本身就会充当self:
result = class MyClass
puts self
"return value"
end
puts result
以上语句输出:
MyClass
return value
当前类
对象调用方法需要一个当前对象(self)作为接收者 ,如何来获取当前对象呢?Ruby中,每当通过class打开一个类时,这个类就会成为当前类。事实上,如果self是一个对象,那么当前类就是这个对象的类。所以在顶级上下文中,self = main,main.class = Object,所以当前类就是Object。
上一篇随笔中,我们知道可以用上下文探针Object#instance_eval()方法,该方法可以使调用的对象成为self,并且传递块来访问修改该对象。在类中,也有类似的方法:Module#class_eval(),class_eval()方法会使调用类成为当前类,并且修改添加类中的方法、属性。这个方法可以在类名字未知时,修改类的方法和属性。class关键字只能使用常量作为类名,而Module#class_eval则可以使用变量作为类名。
类实例变量和类变量
class MyClass
@var = 1
def self.read
puts @var
end
def read
puts @var
end
def write
@var = 2
end
end
obj = MyClass.new
obj.write
obj.read
MyClass.read
在上面的代码中,执行obj.write时,此时self是obj对象,@var作为obj的一个实例变量,存在于obj中,执行MyClass.read时,@var作为MyClass的类实例变量(强调,类也是对象,MyClass.class = Class,所以类实例变量实际上是Class类对象的实例变量),存在于MyClass中,不能被子类和实例所访问。
如果要在类中定义一个变量并且可以被子类继承,则需要用到类变量,类变量是由@@开头的变量:
class MyClass
@@var = 1
end
如上定义一个类变量@@var,就可以被class MySubClass < MyClass类继承该类变量。
类变量有一个问题,他并不属于类本身,而是属于类体系结构:
@@var = 1
class MyClass
@@var = 2
end
puts @@var
上述代码会有警告:warning: class variable access from toplevel
由于@@var = 1执行时,self=main,main.class = Object,所以@@var属于Object,同时也属于Object的所有后代,包括MyClass,所以,在顶级上下文中使用类变量是比较危险的行为,同时,也应该减少类变量的使用,而用类实例变量来代替。
类方法
由于类也是一个对象,所以类也可以调用方法:
my_obj.my_method
MyClass.my_class_method
当一个对象调用方法时,其实是一个变量引用的对象调用了方法,而当一个类调用方法时,其实是一个常量引用的对象(Class 的实例) 调用了方法。
在之前学习动态调用时,使用到self.define_component()传入一个参数作为方法名字并且动态定义该方法:
class Computer
def self.define_component(name)
define_method(name){
puts "getting #{name} info"
puts "getting #{name} price"
}
end
define_component :mouse
end
此时,self是Computer,所以define_component就是一个类方法,并且可以在Computer中直接调用define_component方法,这样的方法称为类宏。
类宏在很多的地方都有很好的应用,比如在类中添加一个属性,则需要添加一个读方法和一个写方法对一个实例变量进行操作,这样的方法定义在很多的类中都会重复操作,这时,使用Module#attr_writer()、Module#attr_read()、Module#attr_accessor()就可以
意识到对象的方法应该存放在类中,那么类的方法应该存放于Class中,那样的话,正如继承自类的对象都会有类的实例方法,是否其他的类也会有这个类方法了呢?
class MyClass
def self.my_class_method
"This is a class_method"
end
end
class MyClass2
end
puts MyClass.methods.grep(/my_class_method/)
puts MyClass2.methods.grep(/my_class_method/)
puts Class.instance_methods.grep(/my_class_method/)
事实上,上述代码只会打印一行”This is a class_method“,也就是说,该类方法只存在于MyClass中,而不是Class的实例方法,更加不会被其他的类所继承,那么类方法到底存放在哪里呢?
单件方法和单件类
在Ruby中,对象的类型是鸭子类型,也就是说,一个对象的类型并不是由他的类所决定,而是看它能响应哪些方法。对象只是继承了类中的方法,同样,他也可以有自己独一无二的方法,这个方法就称为单件方法:singleton_methods。由于这个方法是对象所独有,并不存在于对象的类中,那么这个单件方法是如何被调用的呢?
每个对象都有一个隐藏的类:单件类:EigenClass,当一个对象存在单件方法时,会先从对象的单件类中查找,而对象单件类又继承于该对象的类,所以如果在单件类中无法找到,则顺其自然地从父类也就是对象的类中查找,然后和一般的方法一样从祖先链中查找,直到找到或者找不到而调用missing_method。
类也是对象,所以也有单件类方法,所以类也有一个EigenClass,并且EigenClass的父类就是父类的EigenClass,所以类方法可以被子类所调用,但是却不能被其他的类所访问。
EigenClass也是一个类,所以EigenClass也有一个EigenClass。
Ruby中,可以使用以下方式访问单件类:
class << MyClass
def my_singleton_class
end
end
同时,MyClass如果是obj就是给对象添加一个单件方法, class << 就表示需要访问谁的单件类。
知道了这一点,就可以给类也添加属性。一个对象的属性就是对对象的实例变量实现读写操作,类的属性就是对类实例对象实现读写操作,用类宏实现:
class MyClass
attr_accessor :a
class << self
attr_accessor :b
end
end
现在,MyClass有一个实例属性a,并且有一个类属性b,并且该属性不会被其他类访问而打乱整个命名空间,会被子类继承。
通过模块可以批量添加一些打包好的类实例方法,那么如何通过模块来添加类方法呢?
class MyClass
include MyModule1
class << self
include MyModule2
end
end
此时,MyClass中添加了MyModule1中的方法作为实例方法,并且添加了MyModule2中的方法作为类方法。这种应用相当普遍,所以有Object#extend()方法专门处理这些问题:
class MyClass
extend MyModule2
end
obj = MyClass.new
obj.extend MyModule1
extend方法实际上在接收者的EigenClass中包含了模块的快捷方式。
别名
通过alias关键字可以给方法添加一个别名,alias :another_name :my_method,注意中间没有逗号,因为alias是一个关键字而不是方法(关键字又是在结构的什么位置中,和方法的区别又是什么呢?)。调用新的名字时,会调用添加别名时的原来的方法。
对命名了别名后的方法进行重定义,那么别名方法引用的还是原始方法,根据这个特性,可以实现环绕别名的技术:
class MyClass
alias :real_length :length
def length
real_length > 5 ? ‘long’ : ’short’
end
end
MyClass#length方法调用别名real_length时,其实调用的是原始的length方法,这种方式有点类似于汇编语言中经常用到的保护现场, 在gem中用环绕别名实现版本控制。环绕别名是一个猴子补丁,可能会造成冲突的问题,在使用时尤其要注意。
Ruby学习之深入类的更多相关文章
- Ruby学习(三)——类与对象(1)
今天看了<Ruby元编程>,感觉内容新颖翔实,是Ruby中难得的一见的好书,在此推荐给大家.其实今天看的主要是第一章的第一部分,先把内容梳理一下,也许这一部分会分成几天的内容来给大家介绍吧 ...
- Ruby学习之mixin
直接上代码: module Action def jump @distance = rand(4) + 2 puts "I jumped forward #{@distance} feet! ...
- Ruby on Rails (ROR)类书籍
Ruby on Rails (ROR)类书籍下载地址及其他(整理) Ruby on Rails 如此之热,忍不住也去看了看热闹,现在把一些相关的电子图书下载地址整理下,方便有兴趣的朋友. 2006-0 ...
- ruby 学习笔记 1
写ruby blog 系统的记录下.也是对我学ruby的点滴记录. 先介绍下我的学习环境.系统:ubuntu12.04文档:techotopia ,ruby文档,the hard way learn ...
- Yaf零基础学习总结5-Yaf类的自动加载
Yaf零基础学习总结5-Yaf类的自动加载 框架的一个重要功能就是类的自动加载了,在第一个demo的时候我们就约定自己的项目的目录结构,框架就基于这个目录结构来自动加载需要的类文件. Yaf在自启动的 ...
- Ruby学习心得之 Linux下搭建Ruby环境
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Ruby学习心得之 Linux下搭建Ruby环境1.前言2.Linux下安装Ruby环境 一 ...
- ruby学习网站
Ruby官方中文网(推荐): https://www.ruby-lang.org/zh_cn/ 国内非常不错的Ruby学习教程网站(推荐): http://www.yiibai.com/ruby Ru ...
- JAVAAPI学习之Calendar类;Calendar类set()、add()、roll()方法区别
JAVAAPI学习之Calendar类 http://blog.csdn.net/myjlvzlp/article/details/8065775(写的很好,清晰易懂) Calendar类set(). ...
- java学习一目了然——File类文件处理
java学习一目了然--File类文件处理 File类(java.io.File) 构造函数: File(String path) File(String parent,String child) F ...
随机推荐
- 基于Spring Aop实现类似shiro的简单权限校验功能
在我们的web开发过程中,经常需要用到功能权限校验,验证用户是否有某个角色或者权限,目前有很多框架,如Shiro Shiro有基于自定义登录界面的版本,也有基于CAS登录的版本,目前我们的系统是基于C ...
- 二叉树的递归遍历 Tree UVa548
题意:给一棵点带权的二叉树的中序和后序遍历,找一个叶子使得他到根的路径上的权值的和最小,如果多解,那该叶子本身的权值应该最小 解题思路:1.用getline()输入整行字符,然后用stringstre ...
- 第五章 MVC之 FileResult 和 JS请求二进制文件
一.FileResult 1.简介 表示一个用于将二进制文件内容发送到响应的基类.它有三个子类: FileContentResultFilePathResultFileStreamResult 推荐阅 ...
- 【DevOps】团队敏捷开发系列--开山篇
随着软件发布迭代的频率越来越高,传统的「瀑布型」(开发-测试-发布)模式已经不能满足快速交付的需求.2009 年左右 DevOps 应运而生,开发运维一体化,通过自动化工具与流程让整个软件开发构建.测 ...
- Java基础(十一) Stream I/O and Files
Java基础(十一) Stream I/O and Files 1. 流的概念 程序的主要任务是操纵数据.在Java中,把一组有序的数据序列称为流. 依据操作的方向,能够把流分为输入流和输出流两种.程 ...
- 【Java入门提高篇】Day11 Java代理——JDK动态代理
今天来看看Java的另一种代理方式--JDK动态代理 我们之前所介绍的代理方式叫静态代理,也就是静态的生成代理对象,而动态代理则是在运行时创建代理对象.动态代理有更强大的拦截请求功能,因为可以获得类的 ...
- 总结一下现在关于Design Support Library的几个博客
原文转载:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0713/3179.html 关于Design Support Libr ...
- day02-多线程之线程安全
/** * 线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的. * synchronized:可以在任意对象及方法上加锁, ...
- MVC+EF 入门教程(三)
一.前言 上一节,我们将了生成数据库,那么这张我就将操作设计库. 二.在 Aplication 定义服务 在 Application 中添加文件夹(Blog)和 操作类(BlogServer).实例如 ...
- 中国IT职业培训市场经历的几波浪潮,未来的浪潮又是那一波?
第一波 电脑普及性培训时代 2000年至2003年左右,中国正处于PC计算机普及阶段,而IT职业教育也刚开始兴起,这一波浪潮主要以计算机办公自动化.平面设计.计算机硬件维修.为主:几家大的IT培训机构 ...