6.了解Ruby如何构建继承体系
7.了解super的不同行为
8.初始化子类时调用super
9.提防Ruby最棘手的解析
10.推荐使用Struct而非Hash存储结构化数据
11.通过模块中嵌入代码来创建命名空间
12.理解等价的不同用法
13.通过“<=>”操作符实现比较和比较模块
14.通过protected方法共享私有状态
15.优先使用实例变量而非类变量
6.了解Ruby如何构建继承体系
明确两个概念:对象:是指向类的引用和实例变量的容器;类:是常量和实例方法的容器
#继承体系就是方法的查找顺序
单例类>prepend>类本身>include>Object>Kernel>BasicObject
#include多个时,遵循lifo(后进先出原则)原则
#继承中的方法示例
ancestors #返回继承体系中的类和模块
included_modules #返回继承体系中的模块
singleton_class #返回继承体系中的单例类
其他的具体用法和实例从元编程的Object中查找。
7.了解super的不同行为
method中super已经做了介绍
8.初始化子类时调用super
initialize是私有实例方法,子类如果没有重写这个方法,会默认继承父类的initialize,类调用new方法时,会自动调用initialize方法
class Father
def initialize
@name = "jayzen"
end
def to_s
"#{self.class}"+" #{@name}"
end
end
class Child < Father
end
obj = Child.new
#默认继承了父类的initialize
puts obj #=>Child jayzen
子类自定义initialize方法时,会对父类的initialize进行重载(方法名字相同,但是方法参数不同),但是子类不会调用父类的被重载的方法initialize,就是说子类一旦定义了initialize方法,父类的initialize方法就不会被执行
class Parent
attr_accessor :name
def initialize
@name = "world"
end
end
class Child < Parent
attr_accessor :grade
def initialize
@grade = "12"
end
end
youngster = Child.new
#因为继承了父类的attr_accessor :name
puts youngster.respond_to?(:name) #true
#没有调用父类的initialize方法,因此该值为nil
puts youngster.name #nil
使用super方法初始化父类
class Parent
attr_accessor :name
def initialize
@name = "jayzen"
end
end
class Child < Parent
attr_accessor :grade
def initialize
super
@grade = “marshal”
end
end
youngster = Child.new
puts youngster.name #=>jayzen
puts youngster.grade #=>Marshal
使用super方法使用参数初始化父类
class Parent
attr_accessor :name
def initialize(name)
@name = name
end
end
class Child < Parent
attr_accessor :grade
def initialize(name, grade)
super(name)
@grade = grade
end
end
youngster = Child.new("jayzen", "Marshal")
puts youngster.name #=>jayzen
puts youngster.grade #=>Marshal
9.提防Ruby最棘手的解析
setter方法中已经做了说明
10.推荐使用Struct而非Hash存储结构化数据
类struct中已经做了说明
11.通过模块中嵌入代码来创建命名空间
常量查找中已经做了说明
12.理解等价的不同用法
方法equal?中已经介绍了equal?, eql?, ==, ===四种比较方法
13.通过“<=>”操作符实现比较和比较模块
类comparable中已经介绍了<=>方法的使用
14.通过protected方法共享私有状态
权限设置中已经说明了protected的作用
15.优先使用实例变量而非类变量
概念:对象是由指向类的引用和实例变量构成的。类其实也是对象,类本身也有实例变量,但是类的实例变量只有在定义了类方法的时候才能被访问到。
class Demo
def initialize
@address = "tianjin"
end
def self.demo
@name = "jayzen"
end
end
Demo.demo #只有类方法被调用类的实例变量才能被类发现
obj = Demo.new
p Demo.instance_variables.grep(/@name/) #[@name]
p obj.instance_variables.grep(/@address/) #[@address]
使用类变量设计单例模式
class Demo
private_class_method(:new, :clone, :dup)
def self.instance
@@single ||= new
end
end
p Demo.instance #<Demo:0x00007fcc33876048>
p Demo.instance #<Demo:0x00007fcc33876048>
在上面的代码中,第一次调用Demo.instance的时候@@single为nil,会执行后面的new方法,因此第一次调用instance的时候执行了两个动作
1.调用了new方法
2.将Demo的实例变量赋值给@@single
但是如果使用两个继承自Demo的子类
class Demo
private_class_method(:new, :clone, :dup)
def self.instance
@@single ||= new
end
end
class Confirmation < Demo
end
class Database < Demo
end
p Confirmation.instance #<Confirmation:0x00007fe9da8d99d0>
p Database.instance ##<Confirmation:0x00007fe9da8d99d0>
上面的代码中两个继承的子类都是生成的第一个子类的instance方法所生成的实例对象。原因在于子类会继承父类的类方法,并且子类会共享父类中的类实例变量,子类和子类实例对象可以修改这个类实例变量。解决方法是将类实例变量改变为实例变量。
class Demo
private_class_method(:new, :clone, :dup)
def self.instance
@single ||= new
end
end
class Confirmation < Demo
end
class Database < Demo
end
p Confirmation.instance #<Confirmation:0x00007facc916d780>
p Database.instance #<Database:0x00007facc916d618>