メソッドのオーバーライド
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]チャレンジ
簡単給与計算のクラスを完成させてください。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}"
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rubyオンラインコンパイラ