Menu
CoddyTech

重写方法

本课属于 Coddy Ruby 学习旅程的“面向对象编程”单元。第 23 课,共 57 课。

子类可以通过定义一个同名方法来重写该方法。Ruby 会先在对象所属的类中查找方法,只有找不到时才会在父类中查找,因此会使用子类中的版本:

class Animal
  def speak
    "..."
  end
end

class Dog < Animal
  def speak
    "Woof"
  end
end

class Fish < Animal
end

puts Dog.new.speak
puts Fish.new.speak

输出:

Woof
...

对于子类对象,调用另一个方法的超类方法会使用被重写的方法。共享的方法只需编写一次,每个子类只需修改不同的部分:

class Animal
  def initialize(name)
    @name = name
  end

  def introduce
    "#{@name} says #{speak}"
  end

  def speak
    "..."
  end
end

class Cat < Animal
  def speak
    "Meow"
  end
end

puts Cat.new("Tom").introduce
puts Animal.new("Thing").introduce

输出:

Tom says Meow
Thing says ...

在子类中重写 to_s,只会改变该子类的打印方式。没有重写的方法仍然来自超类:

class Item
  def initialize(name, price)
    @name = name
    @price = price
  end

  def to_s
    format("%s %.2f", @name, @price)
  end
end

class SaleItem < Item
  def to_s
    format("%s %.2f (sale)", @name, @price * 0.8)
  end
end

puts Item.new("Lamp", 20)
puts SaleItem.new("Lamp", 20)

输出:

Lamp 20.00
Lamp 16.00 (sale)

Ruby 搜索的顺序是类的祖先类:先是类本身,然后是它的父类,以此类推,直到 Object。列表中第一个定义了该方法的类会提供这个方法:

class Animal
  def speak
    "..."
  end
end

class Dog < Animal
  def speak
    "Woof"
  end
end

class Puppy < Dog
end

puts Puppy.new.speak
p Puppy.ancestors.take(3)

输出:

Woof
[Puppy, Dog, Animal]
challenge icon

挑战

简单

完成工资类。Employee 保存一个 name,并有 pay(hours),它会返回 hours * 20;还有 payslip(hours),它会使用 pay 返回 Ada: 800。无论工时是多少,Manager 都会重写 pay,返回固定的 1500。Intern 会重写 pay,返回 hours * 12,但最多为 300。payslip 只在 Employee 中定义。

提供的代码会读取以下行:employee Ada 40、manager Bo 50 或 intern Cy 20,创建匹配的对象并打印工资单,然后打印总工资。

你的代码应写在 employee.rb、manager.rb 和 intern.rb 中。main.rb 包含提供的输入/输出代码,不能编辑。

亲手试试

require_relative 'employee'
require_relative 'manager'
require_relative 'intern'

# 提供的输入和输出代码:保持原样
input = []
while (line = gets)
  input << line.chomp
end
kinds = { "employee" => Employee, "manager" => Manager, "intern" => Intern }
total = 0
input.each do |line|
  kind, name, hours = line.split
  worker = kinds[kind].new(name)
  puts worker.payslip(hours.to_i)
  total += worker.pay(hours.to_i)
end
puts "total: #{total}"
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Ruby 在线编译器