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>

results matching ""

    No results matching ""