1.类定义和当前类
1.在类定义中,当前对象self就是正在定义的类,当前类就是self就是正在定义的类。
2.如果有一个类的引用,则可以用class_eval()方法打开这个类。
def add_method_to(a_class)
a_class.class_eval do
#class_eval的别名是module_eval
def m
puts "hello"
end
end
end
add_method_to String
"abc".m #=>"hello"
3.方法中定义方法
class MyClass
def method_one
def method_two
puts "hello"
end
end
end
obj = MyClass.new
obj.method_one #调用method_one,定义method_two
obj.method_two
2.类实例变量
1.所有的实例变量属于当前self,属于当前类的实例变量是类实例变量
2.类实例变量只能被类本身所访问,而不能被类的实例或者子类所访问
class MyClass
@my_var = 1
def self.read
@my_var
end
def write
@my_var = 2
end
def read
@my_var
end
end
obj = MyClass.new
obj.write
puts obj.read #>2
puts MyClass.read #>1
#访问这个变量不是说通过这个类或者类的对象直接调用这个变量
MyClass.my_var #=>undefined method my_var
#而是通过调用方法的形式调用这些变量,代码如下所示:
obj.read #>2
MyClass.read #>1
3.类变量
1.和类实例变量不同,类变量可以被子类或者类的实例所使用
2.类变量不属于真正的类,他们属于类体系结构
class MyClass
@@my = 1
def self.read
@@my_var
end
def write
@@my_var = 2
end
def read
@@my_var
end
end
class SonClass < MyClass
end
son_obj = SonClass.new
puts son_obj.read #=>1
obj = MyClass.new
obj.write
puts obj.read #=>2
puts MyClass.read #=>2
#下面的代码说明类变量不属于真正的类,他们属于类体系结构。
@@v = 1
class MyClass
@@v = 2
end
puts @@v #=>2
#warning class variable access from toplevel
# @@v定义于main的上下文,它属于main的类Object,所以也属于Object的所有后代
4.使用Class定义类
#定义一个Array的子类:
class MyClass < Array
def my_method
puts "hello"
end
end
#不使用class关键词定义Array的子类:
c = Class.new(Array) do
def my_method
puts "hello"
end
end
MyClass = c
puts c.name #=>MyClass
#类是匿名类,类名其实是常量,如下的形式给类进行赋值:
MyClass = c
#从最后一句可以知道c.name是这个类的名字。
#其实直接给类进行常量赋值也是可以的,见如下的代码:
MyClass = Class.new(Array) do
def my_method
puts "hello"
end
end
obj = MyClass.new
obj.my_method
5.单件方法
1.针对单个对象生效的方法叫做单件方法,类方法也是单件方法,类也是对象
#如下代码是字符串对象生成单件方法:
str = "just a regular string"
def str.title?
self.upcase ==self
end
#类方法的三种形式
class MyClass
def MyClass.method_one
puts "this is the method_one"
end
def self.method_two
puts "this is the method_two"
end
class << self
def method_three
puts "this is the method_three"
end
end
end
6.类宏
1.attr_accessor()这样的方法被成为类宏,是普通的方法,可以用在类定义中。
#类宏的真实形式
class MyClass
def my_attribute=(value)
@my_attribute = value
end
def my_attribute
@my_attribute
end
end
obj = MyClass.new
obj.my_attribute = "x"
puts obj.my_attribute #=>"x"
#上面的代码的简化形式
class MyClass
attr_accessor :my_attribute
#定义两个方法和一个实例变量
end
obj = MyClass.new
obj.my_attribute = "x"
puts obj.my_attribute #=>"x"
#类宏进行应用
class Book
def title
puts "this is the title"
end
def self.deprecate(old_method, new_method)
define_method(old_method) do |*args, &block|
warn "Warning :#{old_method}() is deprecated, use #{new_method}()"
send(new_method, *args, &block)
end
end
deprecate :GetTitle, :title #调用和定义方法
end
book = Book.new
book.GetTitle #=>结果为预期所示
7.单件类
1.为了补全对象模型的知识,找到单件方法的藏身之所。
2.我们称单件方法所在的类为单件类。
3.单件类是一个特殊的类,它只有一个实例,并且不能被继承。
4.一个对象的单件类的父类是这个对象的类。
5.一个类的单件类的超类是这个类的超类的单件类。
#获得eigenclass:
obj = Object.new
eigenclass = class << obj
self
end
#通过class << obj的形式可以进入obj单件类的领域中
#这里的self对象就是单件类,整个返回的就是一个单件类
puts eigenclass.class #=>Class
#为了方便查找对象的eigenclass,在Object类中定义了如下的代码:
class Object
def eigenclass
class << self
self
end
end
end
#任何类(除了BasicObject)都是继承于Object,因此此方法eigenclass能适用于所有的对象
#任何对象调用eigenclass方法,返回的都是该对象的单件类。
#对象单件方法表示形式:
obj = Object.new
class << obj
def a_singleton_method
puts "this is the obj singleton method"
end
end
obj.a_singleton_method #=>this is the obj singleton method
#演示如何寻找单件类的父类:
class Object
def eigenclass
class << self
self
end
end
end
class C
def a_method
puts "this is the class C method"
end
end
class D < C
end
obj = D.new
obj.a_method
class << obj
def a_singleton_method
puts "this is the singleton method"
end
end
#对象单件类的父类是该对象的类
obj.eigenclass.superclass #=>D
对象模型查找方法补充:
1.对象有eigenclass,从这个eigenclass类中开始查找方法。
2.在eigenclass类中找不到方法,那么它会沿着祖先链向上来到eigenclass的超类。
class Object
def eigenclass
class << self
self
end
end
end
class C
class << self
def a_class_method
puts "C.a_class_method"
end
end
end
class D < C
end
obj = D.new
obj.a_method
C.eigenclass #=>#<Class:C>
D.eigenclass #=>#<Class:D>
D.eigenclass.superclass #=>#<Class:C>
C.eigenclass.superclass #=>#<Class:Object>
结论:类的单件类的父类是其类的父类的单件类
#D(D类的eigenclass)的超类是#C,#C的超类是#Object,于是可以在子类调用父类的类方法
D.a_class_method #=>"C.a_class_method"
8.类属性
1.对象属性就是通过对象调用方法来达到访问属性的目的
2.类属性就是直接通过类名直接调用属性的方式
class MyClass
attr_accessor :a
end
obj = MyClass.new
obj.a = 2
abj.a #=>2
class MyClass
end
class Class
attr_accessor :b
end
MyClass.b = 42
MyClass.b #=> 42
1.类MyClass是类Class的对象,因此类MyClass可以直接调用类Class的实例方法,
2.如果是专属于MyClass的属性,需要另外一种技术,是添加类方法的另外一种形式:
class MyClass
#打开eigenclass域,定义类方法,通过类宏的形式,可以获得类的属性
class << self
attr_accessor :c
end
end
MyClass.c = "this is class singleton attribute"
MyClass.c #=>"this is class singleton attribute"
9.类扩展和对象扩展
1.类中include一个具有模块方法的模块,该方法是该类的类方法,也是该类单件类的实例方法,这种技术叫类扩展。
2.将上面的类扩展应用到任意对象上,叫做对象扩展。
#当类包含模块时,获得的是该模块的实例方法,而不是类方法
#而模块中的类方法存在于模块的eigenclass中,无法触碰。
module MyModule
def self.my_method
puts "hello"
end
end
class MyClass
include MyModule
end
MyClass.my_method #NoMethodError!
#将模块引入到类的eigenclass中,这样子类就可以将模块中的实例方法作为类方法引入:
module MyModule
def my_method
puts "hello"
end
end
class MyClass
class << self
include MyModule
end
end
MyClass.my_method #=>hello
#上面的技术是类扩展,应用到任意对象上是对象扩展
module MyModule
def my_method
puts "hello"
end
end
obj = Object.new
class << obj
include MyModule
end
obj.my_method #=>hello
obj.singleton_methods #=>[:my_method]
#使用Object#extend方法也可以实现类扩展和对象扩展
module MyModule
def my_method
puts "hello"
end
end
obj = Object.new
obj.extend MyModule
obj.my_method #=>hello
class MyClass
#是self.extend的省略形式
extend MyModule
end
MyClass.my_method #=>hello
#extend是Object类的方法,所以对象obj可以调用该方法
#MyClass可以直接调用extend方法,MyClass是Class类的对象,而Class类的祖先链包括Object,在类中可以直接使用该类的类方法:
class MyClass
def MyClass.class_method
puts "this is the class method"
end
class_method #=>this is the class method
end
10.方法包装器:别名
作用:有一个不能直接修改的方法,因为这个方法在库中,希望这个方法包装额外的特性,所有的客户端都能自动获取这个额外特性。
环绕别名:
1.给方法定义一个别名
2.重定义这个方法
3.在新的方法中调用老的方法
#使用关键字alias:
class MyClass
def my_method
puts "this is my method"
end
alias :m :my_method #关键字alias,不用加逗号
end
obj = MyClass.new
obj.my_method #=> this is my method
obj.m #=> this is my method
#使用alias_method方法
class MyClass
alias_method :m2, :m
end
obj.m2 #=> this is my method
#环绕别名
class String
alias :real_length :length
def length
real_length > 5 ? "long" : "short"
end
end
"war and peace".length #=> long
"war and peace".real_length #=> 13
11.方法包装器:细化封装器
#细化中调用super方法,则会调用那个没有细化的原始方法
module StringRefinement
refine String do
def length
super > 5 ? 'long' : 'short'
end
end
end
using StringRefinement
"war and peace".length #=>"long"
12.方法包装器:下包含包装器
#使用module#prepend方法,会把模块插入到祖先链到该类的下方,而非上方
#通过super调用该类中的原始方法
module ExplicitString
def length
super > 5 ? 'long' : 'short'
end
end
String.class_eval do
prepend ExplicitString
end
"war and peace".length #=>'long'