我、"モジュール化 / メソッド化"に出会う
状況
- 本日は、以前書いたRakeタスクに対して、「ここのロジックはメソッド化できるのでは」とアドバイスいただきました。
- 相変わらず、「メソッド化とは何か」からわからなかったので調べてみました。
- メソッド化を調べるにあたって、「モジュール」「モジュール化」の概念の理解が必要そうだったのでそちらから記載してみます。
モジュールについて調べてみた
Rubyのモジュールとは?
Rubyのモジュールは、ある機能やメソッドをひとまとめにして「部品化」し、クラスに取り込んで再利用できる仕組みです。クラスのように“new”でインスタンス化はできませんが、2つの大きな役割があります。
-
名前空間(namespace)としての利用
モジュールの中にクラスや定数などをまとめることで、名前の衝突を避けるために使います。 -
Mixinとしての利用
「あるクラスに特定の機能(メソッド)を追加したい」ときに使います。Rubyでは多重継承はできませんが、モジュールを使うことで多重継承っぽい機能拡張を実現できます。
1. 名前空間としての利用例
同じ名前のクラスや定数が共存していると、Rubyは「どのクラスを使えばいいのか分からない!」となってしまいます。これを防ぐために、**モジュール名を“入れ物”**として使い、名前の衝突を避けます。
# moduleを名前空間として利用
module MyLibrary
VERSION = "1.0.0"
class MyClass
def greet
puts "Hello from MyLibrary::MyClass"
end
end
end
# 実際に使うとき
puts MyLibrary::VERSION
obj = MyLibrary::MyClass.new
obj.greet
上記のようにMyLibrary
モジュールを名前空間として利用することで、他のライブラリと同じ定数名やクラス名を使っていても衝突を回避できます。
2. Mixinとしての利用例
Mixinとは?
Rubyはクラスの多重継承ができません。しかし、モジュールを使って「特定のメソッドの集まり」をまるごとクラスに取り込むことができます。これを**Mixin(ミックスイン)**と呼びます。
include と extend の違い
- include: モジュールをインスタンスメソッドとして取り込みます。
- extend: モジュールをクラスメソッドとして取り込みます。
include を使った例
module Greetable
def hello
puts "Hello!"
end
def hi
puts "Hi!"
end
end
class Person
# PersonクラスにGreetableモジュールのメソッドを“インスタンスメソッド”として取り込む
include Greetable
end
person = Person.new
person.hello # => "Hello!"
person.hi # => "Hi!"
include Greetable
によって、Person
オブジェクトにhello
とhi
というインスタンスメソッドが追加されます。
extend を使った例
module Loggable
def log(message)
puts "[LOG] #{message}"
end
end
class Robot
# ロボットの共通ログをとる機能をクラスメソッドとして取り込みたい場合
extend Loggable
end
Robot.log("System check") # => [LOG] System check
extend Loggable
を使うと、log
メソッドはクラスメソッドとしてRobot.log
という形で使えるようになります。
じゃあメソッド化ってなに?
モジュール化とメソッド化の違いを簡単に言うと、「機能のまとまり方と再利用方法が異なる」ということです。それぞれの特徴と違いをわかりやすく説明します。
モジュール化とメソッド化の違い
1. モジュール化とは?
モジュール化は、関連する複数のメソッドや定数、クラスをひとまとめにして再利用しやすくする方法です。モジュールを使うと、共通の機能や振る舞いを他のクラスやモジュールに簡単に組み込むことができます。
- 目的: 機能の集約・再利用性向上。
-
再利用の範囲:
他のクラスやモジュールに取り込むことで、その機能を何度も使い回せる。 -
例:
ユーティリティ機能(ログ記録、計算処理など)、名前空間の管理。
モジュール化の具体例
module StringUtils
def capitalize_all(words)
words.split.map(&:capitalize).join(' ')
end
def reverse_string(string)
string.reverse
end
end
class TextFormatter
include StringUtils
end
formatter = TextFormatter.new
puts formatter.capitalize_all("hello world") # => "Hello World"
puts formatter.reverse_string("hello") # => "olleh"
この例では、StringUtils
モジュールを使うことで、文字列操作のロジックをTextFormatter
クラスに簡単に再利用しています。
2. メソッド化とは?
メソッド化は、特定の処理や計算などをひとつの単位(関数)として定義することです。メソッド化された処理は、そのメソッドを呼び出すことで使えます。
- 目的: 1つの処理を単純化・再利用性向上。
-
再利用の範囲:
そのクラスやモジュールの中でのみ使える(スコープに依存)。 -
例:
計算処理やデータフォーマット、状態管理の処理など。
メソッド化の具体例
class Calculator
def add(a, b)
a + b
end
def subtract(a, b)
a - b
end
end
calc = Calculator.new
puts calc.add(5, 3) # => 8
puts calc.subtract(5, 3) # => 2
この例では、add
とsubtract
というメソッドにそれぞれの処理を閉じ込めて使いやすくしています。
モジュール化とメソッド化の違い
比較項目 | モジュール化 | メソッド化 |
---|---|---|
規模 | 複数の機能(メソッドや定数など)を集約したもの | 1つの機能(処理)を定義したもの |
再利用の方法 | 他のクラスやモジュールにinclude /extend で組み込む |
そのクラス・モジュールの中で呼び出して使う |
役割 | 大きな機能をグループ化して整理・再利用性を向上 | 小さな単位での処理を簡潔に書き、再利用性を向上 |
使用範囲 | モジュール全体が外部のクラス・モジュールでも利用可能 | 基本的にクラスやモジュール内でのスコープに限定される |
具体例 | ログ出力機能、データ変換ロジックの共通化など | 計算処理や個別の値変換など、小規模な処理 |
どちらを使うべき?
-
モジュール化が適している場合
- 同じ機能を複数のクラスで使いたい場合。
- ロジックを「まとめて再利用」したい場合。
- 名前空間でクラスやメソッドの整理が必要な場合。
-
メソッド化が適している場合
- 個別の処理を簡潔にまとめたい場合。
- 一度定義した処理をクラス内で繰り返し使いたい場合。
モジュール化とメソッド化を組み合わせた例
module MathUtils
def square(num)
num * num
end
def cube(num)
num * num * num
end
end
class Calculator
include MathUtils
def calculate_square_and_cube(num)
{ square: square(num), cube: cube(num) }
end
end
calc = Calculator.new
puts calc.calculate_square_and_cube(3) # => {:square=>9, :cube=>27}
この例では、モジュール化(MathUtils
)で計算ロジックを再利用し、クラス内のメソッド化で個別の処理をまとめています。
まとめ
-
モジュールはインスタンス化できないが、クラスに機能を付与するために利用できる。
-
名前空間としてクラスや定数をまとめることで衝突を防ぐ。
-
include や extend を使ってクラスの機能を拡張し、コードの再利用性を高められる。
-
メソッドは個別の処理を簡潔にまとめたい場合に利用可能
所見
- モジュールは一つの機能をモジュールファイルに作成して、それをモデルでincludeして使う
- メソッドはもっと細かい一つの処理をそのままモデルや今回ならrakeタスクに使う
- とにかくコードは薄く、後から見やすく、使いやすくを意識することが重要 なのね
Discussion