こんにちは市原です。
以前
「Railsで作ったアプリでよく使う自作メソッドを別ファイルにまとめて、必要ところで使いたいけど、やり方が分からぬ…」
といったことがありました。
意外と分かっているようでわかっていなかったclassとmodule、せっかくなので記事にまとめてみました。
calssとモジュール
ざっくりまとめるとこのようになります。
特徴 | 使用方法 | 継承 | インスタンス | 優位性 | |
---|---|---|---|---|---|
class | データやメソッドをまとめたもの | requireでファイルを読み込んでから継承しインスタンスメソッドとして使用 | 〇 | 〇 | 継承を使って複数のクラスをまとめるため、フレームワーク的な使い方ができる |
module | メソッドや値のみをまとめたもの | reequireでファイルを読み込んでからinclude,extendで使用 | ✖ | ✖ | データをまとめて必要個所で使用する、パーツとして使用 |
class
classは継承やインスタンスの生成を通じてより広い範囲のオブジェクトに影響を与えます。
class Formula
def pythagorean_theorem(a, b)
p "c = #{Math::sqrt(a**2+ b**2)}"
end
def self.quadratic_formula(a, b, c)
x1 = (- b +Math::sqrt(b*b -4*a*c))/ 2 * a
x2 = (- b -Math::sqrt(b*b -4*a*c))/ 2 * a
p "x is #{x1} and #{x2}"
end
end
# requireを使ってまずはファイルを読み込む
require "calc/formulas"
# クラスを継承してメソッドやデータを引き継ぎ
class Hoge < Formula
attr_accessor :name
def initialize(name, age)
@name = name
@age = age
end
end
hoge = Hoge.new("hogehoge",22)
hoge.pythagorean_theorem(3, 4)
#-----------------------------------------------------------
"c = 5.0"
クラスの場合、まずはrequireを使ってファイルを読み込み、使いたいクラスに継承させ、その後インスタンスを生成するという流れになります。
そのためMVCモデルやフレームワークの構築といった、多くのデータを継承しそれぞれの連携を取る際は向いておりますが、ちょっとデータをまとめて使いたいときに使うという目的であれば後述するmoduleの方が適していると言えます。
module
モジュールもclassと同じ値やメソッドをまとめておける役割を持ちますが、インスタンスの生成と継承ができません。
そのため単に情報をまとめておき、必要な場所で呼び出すといった面ではclassよりモジュールの方が使い勝手がいいです。
moduleをclass内で呼び出すにはincludeとextendの2種類があります。
includeとextend
一言で表すとincludeはインスタンスメソッドとしてmoduleを組み込み、extendはクラスメソッドとしてmoduleを組み込みます。
以下では数学の公式をmoduleとしてまとめ、インスタンスメソッドとして呼び出しています。
module Formula
# 三平方の定理
def pythagorean_theorem(a, b)
p "c = #{Math::sqrt(a**2+ b**2)}"
end
# 解の公式
def quadratic_formula(a, b, c)
x1 = (- b +Math::sqrt(b*b -4*a*c))/ 2 * a
x2 = (- b -Math::sqrt(b*b -4*a*c))/ 2 * a
p "x is #{x1} and #{x2}"
end
end
# 読み込み
require "calc/formulas"
class Hoge
attr_accessor :name
# クラス内でincludeを使用
include Formula
def initialize(name, age)
@name = name
@age = age
end
end
hoge = Hoge.new("hogehoge",22)
hoge.pythagorean_theorem(3, 4)
#---------------------------------------------------
"c = 5.0"
このようにHogeクラスから生成されたインスタンスがピタゴラスの定理であるpythagorean_theoremをインスタンスメソッドとして使えるようになっています。
続いてextendで同様に読み込んでみると…
require "calc/formulas"
class Hoge
attr_accessor :name
extend Formula
def initialize(name, age)
@name = name
@age = age
end
def hello
p "Hello! I'm #{@name} "
p "I'm #{@age} old"
end
end
hoge = Hoge.new("hogehoge",22)
hoge.pythagorean_theorem(3, 4)
#--------------------------------------------------------------------
calculate.rb:26:in `<main>': undefined method `pythagorean_theorem' for #<Hoge:0x000000000504a3a8 @name="hogehoge", @age=22> (NoMethodError)
と、生成されたインスタンスはmoduleのメソッドを使うことはできないのが分かります。
Hoge.pythagorean_theorem(3, 4)
#----------------------------------------------------------------
"c = 5.0"
クラスメソッドとして呼び出してあげれば使えます。
ちなみにclass内でmoduleを展開するため、それを継承したクラスでもそれぞれインスタンスメソッド、クラスメソッドを使うことができますよ~
以下はincludeを使ってクラスを継承しました。
class Fuga < Hoge
end
fuga = Fuga.new("fugafuga",20)
fuga.quadratic_formula(1, 3, 2)
#----------------------------------------------------------------
"x is -1.0 and -2.0"
moduleメソッド
いちいちクラスに組み込まずに、ダイレクトでメソッドだけを使いたい場合はmoduleメソッドというものが使えます。
module Formula
def pythagorean_theorem(a, b)
p "c = #{Math::sqrt(a**2+ b**2)}"
end
def quadratic_formula(a, b, c)
x1 = (- b +Math::sqrt(b*b -4*a*c))/ 2 * a
x2 = (- b -Math::sqrt(b*b -4*a*c))/ 2 * a
p "x is #{x1} and #{x2}"
end
# module_function + メソッド名でmoduleメソッドを定義
module_function :quadratic_formula
end
#クラスメソッドと同じ要領で呼び出せる
Formula.quadratic_formula(1, 8, 12)
#---------------------------------------------------
"x is -2.0 and -6.0"
このようにmoduleはclassを作るまでは必要ないが、ちょっと機能を追加したい場合に使えます。
まとめ
データをまとめるだけならmodule、継承を使ってのアプリの一部にデータを組み込みたいならclassを使用するのが望ましいです。