JQ Blog

クラスとインスタンス、モジュールの違い

Rubyはオブジェクト指向プログラミング言語であり、オブジェクトというものをわからなければRubyを正しく理解することはできない。なので、オプジェクト指向とオプジェクトの一般的な概念になるクラスやモジュールをまとめてみる。

オブジェクト指向とは

Ruby, Java, Pythonなどはオブジェクト指向言語というものに分類されている。オブジェクトというものは具体的に識別できるものならなんでもオブジェクトなれる。例えば、文字列、数値、時刻など全てのデータがオブジェクトとして扱われる。"hello, world"とか"object"は文字列オブジェクト、1や3.14などは数値オブジェクトと呼ばれる。
また、オブジェクトはメソッドを通して何かの行動ができる。オブジェクトのメソッドを実行するには下記のようなコードを使う。

1
(オブジェクト).(メソッド名)

クラス、インスタンス

クラスとはオブジェクトの種類を表したものである。Rubyのオブジェクトは必ずクラスに属している。オブジェクトがどんなクラスに属しているかを確認するためには下記のように.classメソッドを使って調べる。

1
2
str = "hello, world!"
p str.class # => String

このクラスというものは設計図になるとしたら、インスタンスはその設計図を使って実際に作り出すものになる。つまり、インスタンスはクラスを具体化したものだということ。そして全てのオブジェクトはあるクラスのインスタンスだとも言える。

実際に使ってみる

1
2
3
4
5
6
7
8
class Greet
  def hello(name)
    p "こんにちは、" + name + "さん"
  end
end

greet = Greet.new
greet.hello("Jo") # => "こんにちは、Joさん"

説明すると

  • クラスを定義する
1
2
3
class クラス名
  # クラスの内容
end
  • メソッドを定義する
1
2
3
def メソッド名
  # 実行する処理
end
  • インスタンスを作成
1
インスタンス名 = クラス名.new

newメソッドを用いることでインスタンスを作成できる。

モジュール

まず、コンソールで試してみたら

1
2
3
4
5
pry(main)> Class.superclass
=> Module

pry(main)> Module.superclass
=> Object

モジュールはクラスのスーパークラスということをわかる。
クラスとモジュールの違いは、リファレンスマニュアルを見ると、こう書かれてる。

クラスとモジュールには

  • クラスはインスタンスを作成できるが、モジュールはできない。
  • モジュールを他のモジュールやクラスにインクルードすることはできるが,クラスをインクルードすることはできない。

という違いがありますが、それ以外のほとんどの機能は Module から継 承されています。Module のメソッドのうち

  • Module#module_function
  • Module#extend_object
  • Module#append_features
  • Module#prepend_features
  • Module#refine

は Class では未定義にされています。

class Class - Ruby 2.3.0 リファレンスマニュアル

上記の特性を見ると、モジュールはあくまでクラスの機能を補助(拡張)するものというイメージ。
下記は一番シンプルな例。

1
2
3
4
5
6
7
8
9
10
11
12
module M
  def foo
    'module method'
  end
end

class C
  include M
end

puts C.new.foo
# => module method

Rubyでのモジュールの役割

大きく二つの役割がある

  • Mix-in
  • Namespace

Mix-in

クラスやモジュールにモジュールをインクルードすることをMix-inと呼ぶ。 Rubyのクラスは多重継承できないが、Mix-inなら複数のモジュールをインクルードすることができる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module M1
  def foo
    'method foo'
  end
end

module M2
  def bar
    'method bar'
  end
end

class C
  include M1
  include M2
end

puts C.new.foo
puts C.new.bar
# => method foo
# => method bar

Namespace

クラス定義をモジュールで囲むことで、Namespaceとして利用できる。異なるNamespaceであれば、同名のクラスも定義できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module M1
  class Foo
    def foo
      'foo'
    end
  end
end

module M2
  class Foo
    def bar
      'bar'
    end
  end
end

puts M1::Foo.new.foo
puts M2::Foo.new.bar
# => foo
# => bar

優先順位

インクルードしたモジュールにスーパークラスと同名のメソッドが定義されていた場合、モジュールが優先される。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module M1
  def foo
    'module foo'
  end
end

class A
  def foo
    'class foo'
  end
end

class B < A
  include M1
end

puts B.new.foo
# => module foo

複数のモジュールをインクルードした場合は、後でインクルードしたモジュールのメソッドが優先。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module M1
  def foo
    'M1 foo'
  end
end

module M2
  def foo
    'M2 foo'
  end
end

class A
  include M1
  include M2
end

puts A.new.foo
# => M2 foo

参照

第2回 クラスとインスタンス 〜Rubyの勉強〜
Rubyのモジュールについて調べた