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オンラインコンパイラ