Ruby入門者必見!ポリモーフィズムを理解するための7つのステップ

Rubyのポリモーフィズムを解説する記事のサムネイルRuby
この記事は約10分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

この記事を読めば、Rubyでのポリモーフィズムについて理解することができるようになります。

Ruby入門者にとって、ポリモーフィズムは難しく感じるかもしれませんが、実際には非常に強力な機能であり、上手に使いこなせるとコードの可読性や保守性を向上させることができます。

この記事では、ポリモーフィズムの基本的な理解から、Rubyでのポリモーフィズムの実現方法、活用したプログラミング例まで、7つのステップで詳しく解説します。

●Rubyとは

Rubyは、まつもとゆきひろ氏によって開発されたオブジェクト指向のプログラミング言語です。

Rubyは、コードの可読性が高く、簡潔であり、初心者でも学びやすい言語とされています。

○Rubyの基本概念

Rubyはオブジェクト指向言語であり、その中心的な考え方は「全てのものはオブジェクトであり、オブジェクト間はメッセージをやり取りする」というものです。

この考え方のもと、Rubyではデータと振る舞いを一緒にまとめたオブジェクトを定義し、それを活用してプログラムを作成します。

●ポリモーフィズムとは

ポリモーフィズムとは、オブジェクト指向プログラミングにおける重要な概念の一つで、同一のインターフェースで異なる動作をすることを指します。

ポリモーフィズムの存在によって、コードの抽象度が上がり、柔軟性と再利用性が向上します。

○ポリモーフィズムの基本

ポリモーフィズムの基本的な考え方は、”同じメッセージを送信しても、そのオブジェクトの型によって異なる振る舞いをする”というものです。

これにより、コードはより一般的な形になり、さまざまなオブジェクトで動作するようになります。

○ポリモーフィズムの利点

ポリモーフィズムがもたらす利点としては、コードの再利用性の向上、可読性の向上、拡張性の向上などがあります。

これらはすべて、コードのメンテナンスを容易にする要素となります。

●Rubyでのポリモーフィズムの実現方法

Rubyでポリモーフィズムを実現する方法は主に3つあります。

それらは、「ダックタイピング」、「継承とオーバーライド」、「モジュールの利用」です。

○ダックタイピング

ダックタイピングとは、オブジェクトのクラスではなく、そのオブジェクトがどのように振る舞うかに注目するプログラミングのスタイルを指します。

つまり、あるオブジェクトが特定のメソッドを持っていれば、そのオブジェクトのクラスは問題ではなく、そのメソッドを呼び出すことができます。

□ダックタイピングのサンプルコード

ダックタイピングのサンプルコードを紹介します。

このコードでは、’Duck’クラスと’Person’クラスが共に’quack’メソッドを持っていることを利用しています。

class Duck
  def quack
    'ガーガー'
  end
end

class Person
  def quack
    '私はアヒルではないが、ガーガーと鳴くことができます。'
  end
end

def make_it_quack(object)
  object.quack
end

duck = Duck.new
person = Person.new

puts make_it_quack(duck)   # 'ガーガー'
puts make_it_quack(person) # '私はアヒルではないが、ガーガーと鳴くことができます。'

このコードでは、’make_it_quack’メソッドは引数として与えられたオブジェクトが’quack’メソッドを持っていることを期待しています。

そのため、’Duck’オブジェクトでも’Person’オブジェクトでも、このメソッドを使って鳴かせることができます。

このように、ダックタイピングはメソッドの存在に基づいてオブジェクトを扱い、異なるクラスのオブジェクトでも同じインターフェースを持つことで一貫した動作を可能にします。

○継承とオーバーライド

Rubyにおけるもう一つのポリモーフィズムの実現方法は、継承とオーバーライドによるものです。

継承は、あるクラス(親クラス)の属性やメソッドを別のクラス(子クラス)が引き継ぐことを指します。

一方、オーバーライドは、子クラスが親クラスから引き継いだメソッドを自身の振る舞いに合わせて新たに定義しなおすことを指します。

□継承とオーバーライドのサンプルコード

継承とオーバーライドを用いたポリモーフィズムの実現例を紹介します。

このコードでは、親クラス’Animal’から子クラス’Dog’と’Cat’が継承し、それぞれ’greet’メソッドをオーバーライドしています。

class Animal
  def greet
    'こんにちは'
  end
end

class Dog < Animal
  def greet
    'ワンワン!'
  end
end

class Cat < Animal
  def greet
    'ニャーン!'
  end
end

def say_greet(animal)
  animal.greet
end

dog = Dog.new
cat = Cat.new

puts say_greet(dog)  # 'ワンワン!'
puts say_greet(cat)  # 'ニャーン!'

このコードの実行結果は、’say_greet’メソッドを呼び出した際に、引数として渡されたオブジェクトのクラスが’Dog’であれば’ワンワン!’、’Cat’であれば’ニャーン!’と出力されます。

これは、’Dog’クラスと’Cat’クラスが’Animal’クラスの’greet’メソッドをオーバーライドし、それぞれ独自の振る舞いを定義しているからです。

このように継承とオーバーライドを用いることで、異なるクラスのオブジェクトでも同じメソッド名によって異なる振る舞いを実現することができます。

これがポリモーフィズムの一例です。

○モジュールの利用

モジュールは、メソッドや定数をまとめた再利用可能なコードの塊であり、Rubyでのポリモーフィズムを実現するためのもう一つの手段です。

モジュールは単体でインスタンス化することはできませんが、他のクラスにミックスインと呼ばれる方法で取り込まれ、そのクラスのインスタンスメソッドとして利用されます。

□モジュールのサンプルコード

モジュールを用いたポリモーフィズムの実現例を紹介します。

このコードでは、’Greetable’というモジュールを作成し、’Dog’クラスと’Cat’クラスにミックスインしています。

module Greetable
  def greet
    "#{self.class}が挨拶します!"
  end
end

class Dog
  include Greetable
end

class Cat
  include Greetable
end

dog = Dog.new
cat = Cat.new

puts dog.greet  # 'Dogが挨拶します!'
puts cat.greet  # 'Catが挨拶します!'

このコードの実行結果は、’Dog’クラスと’Cat’クラスのインスタンスがそれぞれ’greet’メソッドを呼び出した際に、そのクラス名が挨拶文として出力されます。

これは、’Dog’クラスと’Cat’クラスが’Greetable’モジュールをミックスインして’greet’メソッドを共有しているためです。

このようにモジュールを利用することで、異なるクラスのオブジェクトでも同じインターフェースを持つことができ、一貫した振る舞いを実現できます。

これもポリモーフィズムの一形態です。

●ポリモーフィズムを活用したプログラミング

ポリモーフィズムは、オブジェクト指向プログラミングの基本的な特性であり、それぞれ異なるオブジェクトが同じインターフェース(メソッド名など)を通じて、そのオブジェクト固有の振る舞いを実行できる特性を指します。

これにより、プログラムの柔軟性と再利用性が大幅に向上し、コードの簡潔さや読みやすさを保つことができます。

○ポリモーフィズムを活用したコードの例

具体的なコードの例を見てみましょう。

下記のコードでは、’Animal’クラスを親クラスとして、’Dog’クラスと’Cat’クラスがこれを継承し、それぞれ’greet’メソッドをオーバーライドして、犬と猫それぞれの特性を表現しています。

class Animal
  def greet
    'こんにちは'
  end
end

class Dog < Animal
  def greet
    'ワンワン!'
  end
end

class Cat < Animal
  def greet
    'ニャーン!'
  end
end

animals = [Dog.new, Cat.new]

animals.each do |animal|
  puts animal.greet
end

このコードを実行すると、’animals’配列の各要素である犬と猫のオブジェクトがそれぞれ独自の挨拶を出力します。

このコードでは、’Dog’クラスと’Cat’クラスが親クラスの’Animal’から’greet’メソッドを継承し、その振る舞いをオーバーライドしています。

したがって、’Dog’クラスと’Cat’クラスのオブジェクトがそれぞれ独自の’greet’メソッドを持つことになります。

これにより、’Dog’クラスと’Cat’クラスのインスタンスが同じメソッド名(ここでは’greet’)で呼び出されても、それぞれが持つ独自の振る舞いを実行することが可能になります。

これがポリモーフィズムの一例であり、この特性を活用することで、より柔軟なプログラミングが可能になります。

●注意点と対処法

ポリモーフィズムを活用する際にはいくつか注意すべき点があります。

その一つは、異なるクラスのオブジェクトが同じメソッドを共有している場合、そのメソッドの名前や引数は同じであるべきという原則です。

例えば、あるクラスのメソッドが引数を一つ取り、別のクラスの同じ名前のメソッドが引数を二つ取るような状況では、予期せぬエラーが発生する可能性があります。

これを回避するための一つの方法は、親クラスで抽象メソッドを定義しておくことです。

抽象メソッドは具体的な実装を持たず、子クラスでオーバーライドされることを前提としています。

class Animal
  def greet
    raise NotImplementedError, "You must implement #{self.class}##{__method__}"
  end
end

class Dog < Animal
  def greet
    'ワンワン!'
  end
end

class Cat < Animal
  def greet
    'ニャーン!'
  end
end

このコードでは、’Animal’クラスの’greet’メソッドが抽象メソッドとして定義されており、’Dog’クラスと’Cat’クラスではこのメソッドをオーバーライドしています。

このようにして、親クラスでメソッドの「形」を定義しておけば、子クラスでの実装を強制することができます。

もし子クラスで’greet’メソッドが実装されていなければ、’Animal’クラスの’greet’メソッドが呼び出されてエラーが発生します。

このように、抽象メソッドを使用することで、クラス間でのメソッドの共有を管理しやすくし、予期せぬエラーを防ぐことができます。

まとめ

この記事では、Rubyでのポリモーフィズムについて、その概念から具体的なコードの例、そして注意点まで詳細に解説しました。

ポリモーフィズムはオブジェクト指向プログラミングの中心的な概念であり、これを理解し活用することで、より効率的で再利用性の高いコードを書くことが可能になります。

ただし、それぞれのクラスのメソッド間で名前や引数を揃えるこ

とや、抽象メソッドを活用することでエラーを防ぐなど、適切な設計と管理が必要です。

今後もポリモーフィズムを深く理解し、実践的なプログラミングに役立ててください。