Ruby 手册 | 07 - 类的定义

309 阅读3分钟

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

一、类的定义和构造函数

Ruby 中一切皆对象,Ruby 中定义类只需要使用到 class 关键字即可,类定义的形式如下:

class 类名
    def 方法名
        ...
    end
    
end

Ruby 中类的名字首字母必须大写,类中的方法名保持小写。

Ruby 中的类也是对象,是 Class 类的实例,因此会自动获得 Class 类的所有实例方法。

# 定义一个类
class AClass

end

puts AClass.class
puts AClass.class.superclass
puts AClass.class.superclass.superclass
puts AClass.class.superclass.superclass.superclass
puts AClass.class.superclass.superclass.superclass.superclass

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

Class
Module
Object
BasicObject


上述代码中定义了一个 AClass 类,通过调用 class 方法可以查看 AClass 类的所属的类是 Class 类,通过调用 superclass 方法不断输出 AClass 上层所继承的类的类名。

根据输出结果可以确定继承关系如下:AClass <= Class <= Module <= Object <= BasicObject,BasicObject 的父类为空,所以 Ruby 中 BasicObject 是所有类的父类。

创建一个对象的实例是通过继承自 Class 类的 new 方法来完成的,该方法底层调用的是 BasicObject 的 initialize 方法

aClass = AClass.new

Ruby 类中没有类似 Java 的专门的构造函数,但是 Class 类的 new 方法会自动尝试调用 AClass 类中的 initialize 方法,并调用调用 new 方法时传递的参数传递给 initialize 方法,如果 AClass 中定义了 new 方法,那么 Class 中的方法会被覆盖,可能就无法创建对象了

二、定义类方法和属性

Ruby 中定义方法需要使用到 def 关键字,定义方法的形式如下:

def 方法名 参数1 参数2
    ...
end

定义一个 Car 类,定义 run 和 stop 两个类方法以及 turn 实例方法,并实例化 Car 类

class Car
  # 定义类方法
  def self.run
    puts "running"
  end

  # 另一种方式定义类方法
  def Car.stop
    puts "stopped"
  end

  # 定义实例方法
  def turn
    puts "turnning"
  end
end

# 实例化
car1 = Car.new

# 调用实例方法
car1.turn

# 调用类方法
Car.run
Car.stop

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

turnning
running
stopped

而下面这三种调用都会报错:

# 类调用实例方法
Car.turn

# 实例调用类方法
car1.run
car1.stop

报错信息如下:

Traceback (most recent call last):
/ex23.rb:32:in `<main>': undefined method `run' for #<Car:0x00007fd89700e200> (NoMethodError)
Traceback (most recent call last):
/ex23.rb:32:in `<main>': undefined method `run' for #<Car:0x00007f77c403dc50> (NoMethodError)

这是因为 run 和 stop 是类方法,只能通过 Car 类调用,无法通过实例化的 Car 对象 car1 调用,而 turn 是实例化方法,只能由实例化对象进行调用,类是无法调用的。

Ruby 中属性的定义有四个方法:attr、attr_read、attr_write 和 attr_accessor,它们的作用分别是只能定义只读属性(或可读写)、只读属性、只写属性和可读写属性,它们并不是关键字,而是 Module 类提供的方法。

图片.png

attr 在缺省的情况下与 attr_reader 作用相同,不过 attr 能通过一个附件的参数设置属性是否是可写的。

# symbol 值得是属性名,writable 可以为 true 或者 false 值得是是否可读写
attr(symbol, writable=false)

attr :symbolattr_reader :symbol 是等价的。

class Car

  # attr_accssor 定义 Car 类的 bradn 属性
  attr_accessor :brand

  # 方法定义 price 属性
  def price
    @price
  end

  def price=(value)
    @price = value
  end
end

# 实例化
car1 = Car.new

car1.brand = "红旗"
puts car1.brand

car1.price = 320000
puts car1.price

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

红旗
320000

通过方法定义属性太过复杂,推荐使用 attr_xxx 来定义属性,使用 def 定义属性时 IDE 也会提示且可以自动修改为 attr_xxx 的形式定义属性。

三、访问权限控制

Ruby 中的权限访问控制与 Java 中的类似,都是通过 publicprotectedpublic 关键字来实现的访问控制

  • public:该级别的方法可以被任何人调用,没有任何访问控制,默认的级别就是 public 级别
  • protected:该级别的方法只能被定义该方法的类或者子类的实例化对象调用
  • private:与 protected 类似,区别在于 private方法不能明确的被接收者调用,只能被 self 调用(类调用)

修饰方法时一般放在方法的上面一行进行修改时

class Car

  # 默认public
  def run
    puts "running,这是一个 Car 类的 public(默认) 实例方法"
  end

  protected
  def drive
    puts "driving 这是一个 Car 类的 protected 实例方法"
  end

  private
  def stop
    puts "stoped 这是一个 Car 类的 private 实例方法"
  end

  public
  def turn
    puts "turnning 这是一个 Car 类的 public 实例方法"
  end
end

# 定义一个子类
class HQCar < Car

  # 调用父类的 protected 级别的方法
  def sub_drive
    drive
  end

  # 调用父类的 private 级别的方法
  def sub_stop
    stop
  end
end

# 实例化
car1 = Car.new

car1.run
car1.turn

hqCar1 = HQCar.new
hqCar1.sub_drive
hqCar1.sub_stop

执行上述方法,输出结果如下

running,这是一个 Car 类的 public(默认) 实例方法
turnning 这是一个 Car 类的 public 实例方法
driving 这是一个 Car 类的 protected 实例方法
stoped 这是一个 Car 类的 private 实例方法