Ruby 手册 | 08 - 类的继承与扩展

246 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

一、类变量与实例变量

与类方法和实例方法类似,类中的变量也有类变量和实例变量之分,类变量以 @@ 开头,在类对象层次共享,而实例变量以 @ 开头,仅作用与实例对象中,其他相同类的实例对象无法访问。

class Car

  def initialize
    # 创建实例对象时类变量数量加1,并且标记序号给实例变量
    @@car_count = @@car_count + 1
    @car_index = @@car_count
  end

  # 定义一个类变量
  @@car_count = 0

  # 类方法 返回 Car 类的实例数量
  def self.car_count
    @@car_count
  end

  # 返回实例对象的序号
  def car_index
    @car_index
  end

  # 实例方法返回 Car 类所有实例的数量
  def car_count
    @@car_count
  end

end

# 实例化
c1 = Car.new
puts "现在有 #{c1.car_count} 个 Car 实例"

c2 = Car.new
puts "现在有 #{c2.car_count} 个 Car 实例"

puts "c1 的序号为 #{c1.car_index},共有 #{c1.car_count} 个 Car 实例"
puts "c2 的序号为 #{c2.car_index},共有 #{c2.car_count} 个 Car 实例"

执行上述代码,输出结果如下:

现在有 1 个 Car 实例
现在有 2 个 Car 实例
c1 的序号为 1,共有 2 个 Car 实例
c2 的序号为 2,共有 2 个 Car 实例

@@car_count 是类变量,是 c1 和 c2 共享的,@car_index 是实例变量, c1 和 c2 都有自己的实例变量,切不可访问对象的实例变量。

二、类的扩展与继承

类的扩展是动态语言的独有的特性,可以在不断的编码过程中多次定义类,来实现对类的方法和属性进行添加或者修改,如果扩展定义中的方法在原类中已经存在,新的方法则会覆盖旧的方法。

比如我们可以给 Ruby 的 Integer 类进行扩展。

class Integer

  # 扩展新的方法
  def sayIt
    puts "我的值是 #{self }"
  end

  # 覆盖旧的方法
  def abs
    puts "abs 方法暂停使用"
  end

  # 扩展类方法
  def Integer.sayHi
    puts "Hi, I am Integer"
  end

  # 批量扩展类方法
  class << Integer
    def sayHelloAgain
      puts "sayHelloAgain"
    end

    def sayHelloThird
      puts "sayHelloThird"
    end
  end
end

# 实例化
8.sayIt
8.abs
Integer.sayHelloAgain
Integer.sayHelloThird

执行上述代码,输出结果如下

我的值是 8
abs 方法暂停使用
sayHelloAgain
sayHelloThird

继承则可以看做是另一种扩展类的方法,不过是创建一个新的类,然后在父类的基础上再进行扩展,Ruby 中的继承非常简单,只需要在定义类时使用 < 符号即可。

继承在 Ruby 中无处不在,定义类时,其实这个类已经包含了 Class 类的关系。在类方法中 self 关键字指的是类本身,在实例方法中值得是实例化对象, Python 中的 self 指的是实例化对象。

super 关键字用来引用父类的方法。

class Human
  attr_accessor :name, :age

  def say_hi
    puts "Hi,我是 #{name}"
  end

  def say_age
    puts "Hi, 我今年 #{age} 岁"
  end
end

# 创建一个 Human 的子类 Man

class Man < Human
  def gender
    return "Male"
  end

  def say_gender
    puts "Hi,I am #{self.gender}"
  end

  # 调用父类的方法
  def say_hi
    super
    say_age
    say_gender
  end
end

# 实例化
m = Man.new

# 给父类中的属性赋值
m.name = "Tony"
m.age = 30

# 调用父类的方法
m.say_age

# 调用自己的方法
m.say_gender

# 子类中的方法和父类中的方法重名是,优先调用子类的方法
puts "=====开始调用子类和父类中重名的方法 say_hi====="
m.say_hi

执行上述代码,输出结果如下:

Hi, 我今年 30 岁
Hi,I am Male
=====开始调用子类和父类中重名的方法 say_hi=====
Hi,我是 Tony
Hi, 我今年 30 岁
Hi,I am Male

Man 类继承了 Human 类,所以 Man 类中就拥有了 Human 类的属性和方法,可以直接修改属性和调用方法,当父类和子类中有重名的方法时,优先调用子类的方法,并且在方法中可以通过 super 关键字来调用父类的方法。

三、别名

别名可以创建一个新的名字作为对已有的方法、操作符或者全局变量的引用,别名是通过 alias 关键字来定义的

alias 新名字 旧名字

alias 中的名字参数可以是合法的字符也可以师傅好,当为方法起别名时,新的名字将指向原有方法的一个备份,也就是如果后来旧的方法被覆盖重新定义,别名依然后调用就得代码,这一功能常用于实现多态。

class Integer
  # 创建一个 plus 方法的别名
  alias plus +

  def +(val)
    return self.plus(val*2)
  end
end

puts 2 + 1 # 4
puts 2.plus(1) # 3