Ruby

【Ruby】モジュールのミックスインとは?使い方を解説!

※当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

コード

ひでまる
ひでまる
こんにちは!ひでまるです!
今回はRubyのモジュールのミックスインについて学習していくよ!

 

こんな方におすすめ

  • Rubyを学習している人
  • モジュールを理解したい人

 

現場でRubyを使って開発しているので、個人の勉強記録として残します。

 

「モジュール」とは?

一言で表すと「便利な機能をまとめたもので、クラスに機能を追加する仕組み」です。

もう少し詳しく言うと

  • 継承を使わないで、クラスに機能を追加する
  • 複数のクラスに対して、クラスメソッドを追加する

などです。
他にも「名前空間」として使う場合もありますが、今回は上記について解説していきます!
※名前空間に関して知りたい方は、こちらで解説していますので見てみてください。
【Ruby】名前空間とは?モジュールを使った簡単な使い方を解説!

 

「モジュール」の定義方法

module モジュール名
  モジュール定義
end

◎例

module MusicPlayer
  def play_music(song)
    puts "Now playing: #{song}"
  end
end

 

「モジュール」と「クラス」の違い

クラスはインスタンスを作成できますが、モジュールからインスタンスは作成できません。

my_mysic_player = MusicPlayer.new  ❌️

 

クラスは継承できますが、モジュールは他のモジュールやクラスを継承することはできません。

module MusicPlayer < Player ❌️

 

「モジュール」のミックスイン

ミックスインとはモジュールを使ってクラスに機能を追加するこを指します。

Rubyでは、クラスは1つの親クラスしか継承できず、さらに継承はs-a(〜は〜である)という関係が成り立つ場合に限られます。
しかし、実際の開発では「特定の機能を複数のクラスで共有したい」という場面がよくあり、そんなときに便利なのがモジュールになります。
モジュールを使うことで、複数のクラスに共通の機能を柔軟に追加できます。
これにより、多重継承のような柔軟性を持ちながら、シンプルで再利用しやすいコードを書くことができます。

◎例

音楽プレイヤーの機能を例に考えてみます!

module MusicPlayer
  def play_music(song)
    puts "Now playing: #{song}"
  end
end

この「音楽プレイヤー」の機能は、「車」や「パソコン」など、さまざまな場所で使われますよね。

しかし、ここで問題があります。

  • 「車」と「音楽プレイヤー」の間には is-a(〜は〜である)関係は成り立ちません。つまり、「車は音楽プレイヤーである」とは言えないため、継承は適切ではありません。
  • また、Rubyではクラスは1つの親クラスしか継承できないため、「車クラス」や「パソコンクラス」の親クラスに音楽プレイヤー機能を持つクラスが存在しないと、機能を追加することができません。

このような状況では、モジュールのミックスインがとても役立ちます。

ミックスインのサンプルコード

class Car
  include MusicPlayer
end

class Computer
  include MusicPlayer
end

car = Car.new
car.play_music("車で音楽流しちゃう!")  
# => Now playing: 車で音楽流しちゃう!

computer = Computer.new
computer.play_music("パソコンで音楽流しちゃう!")     
# => Now playing: パソコンで音楽流しちゃう!

このように、「車」や「パソコン」でも共通の機能である「音楽プレイヤー」を、モジュールを使って簡単に追加できます。

「include」と「extend」

  • インスタンスメソッドとして追加したい場合は、「include」を使う
  • クラスメソッドとして追加したい場合は、「extend」を使う

◎includeを使ったサンプル

class Car
  include MusicPlayer
end

class Computer
  include MusicPlayer
end

car = Car.new
car.play_music("車で音楽流しちゃう!")  
# => Now playing: 車で音楽流しちゃう!

computer = Computer.new
computer.play_music("パソコンで音楽流しちゃう!")     
# => Now playing: パソコンで音楽流しちゃう!

インスタンスに対して、音楽プレイヤーを呼び出しています。

◎extendを使ったサンプル

module MusicPlayer
  def play_music(song)
    puts "Now playing: #{song}"
  end
end

class Car
  extend MusicPlayer  # クラスメソッドとして追加
end

class Computer
  extend MusicPlayer  # クラスメソッドとして追加
end

Car.play_music("車で音楽流しちゃう!")
# => Now playing: 車で音楽流しちゃう!

Computer.play_music("パソコンで音楽流しちゃう!")
# => Now playing: パソコンで音楽流しちゃう!

インスタンスを作成せずに、直接音楽プレイヤーを呼び出しています。

 

インスタンスメソッド、クラスメソッドの使い分け

「音楽プレイヤー」のように、個々のオブジェクトに依存する機能は、インスタンスメソッドとして追加したほうが良さそうですね!
例えば、車ごとに異なる曲を再生したり、音量や再生リストなどを個別に管理する場合です。

一方で、クラスメソッドとして追加するのが適しているのは、サポートされているフォーマット一覧(例: MP3, WAV, AAC)のように、インスタンスごとに変わらない共通の情報を扱う場合です。
このような情報は、個々のインスタンスに関係なくクラス自体に関連するため、クラスメソッドで提供するのが良さそうです!

 

おわりに

今回はモジュールのミックスインについて学習してみました。
少しでも学習のお役に立てれば幸いです。

 

参考記事

Ruby 3.3 リファレンス

書籍:プロを目指す人のためのRuby入門

-Ruby