はじめに
前回の記事 Ruby 多重継承 Mix-in でクラスの継承が気になっていたところ ポリモーフィズムの記事 がありましたので、やってみました。
継承版
class Animal
def cry(voice: '')
puts "#{voice}"
end
end
class Dog < Animal
def cry(voice: 'わんわん')
super
end
end
class Cat < Animal
def cry (voice: 'にゃー')
super
end
end
Dog.new.cry
Cat.new.cry
流石にもろコピペは回避いたしましたが、Java
で散々やったパターンです。
合成ダックタイピング版
class Animal
def self.cry(animal)
puts animal.cry
end
end
class Dog
def cry(voice: 'わんわん')
voice
end
end
class Cat
def cry (voice: 'にゃー')
voice
end
end
Animal.cry(Dog.new)
Animal.cry(Cat.new)
発想の転換なのかわかりませんが、継承版の方はメソッド側が変化しているのに対し、合成ダック版はオブジェクト側が変化しています。
でも、これの分岐テストってどうやるんでしょうね。
module Animal
def self.cry(animal)
if animal.instance_of?(Dog)
puts 'わんわん'
elsif animal.instance_of?(Cat)
puts 'にゃー'
end
end
end
class Dog; end
class Cat; end
Animal.cry(Dog.new)
Animal.cry(Cat.new)
やっていることは同じだけどダメな例です。
class
が増えるたびにelsif
を追加する必要があるけど追加忘れしたりするパターンです。
合成ダック版はclass Animal
を触る必要がないところが素晴らしいです。
class AnimalCry
def cry(Dog)
puts 'わんわん'
end
def cry(Cat)
puts 'わんわん'
end
end
class Dog; end
class Cat; end
AnimalCry.new.cry(Dog.new)
AnimalCry.new.cry(Cat.new)
C#
だったらこんな感じで通ったような気がします。
引数の型や数を変化させることで同じメソッドが設定できたはず。
Ruby
だと通りませんが。
ダックタイピングって今一理解できなかったのですが、ポリモーフィズムの観点で掴めた様な気がします。
コメント欄にて、@obelisk68 さんと @kts_h さんにいろいろとアドバイスいただき、ありがとうございました。
継承と合成で参照した記事
Goやるなら知っておきたい「Composition over inheritance」
まとめ
- @kat0 さん、ありがとう
- OOPに詳しくなった