すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Rails

【Rails】 9.Rubyのクラスとインスタンスを学ぼう

※ カリキュラムでは、Cloud9のターミナルやエディタを利用します。
まだ用意していない方は「AWS Cloud9を準備しよう」を参考に導入してください。

オブジェクト指向プログラミングの基礎知識

コンピュータに何かしてもらいたいときには、命令や指示を与えるプログラムが必要です。
プログラムとは、コンピュータに作業させる一連の手順を記述したものです。

プログラム

このプログラムを作ることを「プログラミング」といいます。プログラミングでは、コンピュータが理解できる機械語に翻訳しやすい言葉として、プログラミング言語を使います。その際、プログラマの意図した通りの順番でコンピュータが動作するように指示を与えます。

プログラムの表現方法にはいくつかありますが、その中でもRubyに大きく関わる「オブジェクト指向プログラミング」の基礎知識をおさえておきましょう。

オブジェクト指向プログラミングとは

ざっくり説明すると、「オブジェクト指向プログラミングとは、ものを組み立てるように表現するプログラムの記述手法」です。

オブジェクト指向プログラミングのイメージ

もう少し具体的に説明すると、まず「もの」は「オブジェクト」を指します。

それぞれのデータを「オブジェクト」という仮想の物体と捉え、「オブジェクト同士が互いに影響し合う」という関係性によってプログラムの処理を進めます。

オブジェクト指向プログラミングでは、オブジェクトの設計図である「クラス」と設計図に基づいて生成される「インスタンス」が必要になります。

クラスとインスタンスのイメージを図で掴もう

クラスは、オブジェクトの「設計図」に相当するものです。インスタンスは、設計図であるクラスに基づいて生成されるオブジェクトの実物体のことです。

クラスとインスタンス

設計図であるクラスには、オブジェクトの振る舞い(メソッド)や状態(オブジェクト毎のデータ)を定義します。

たとえとしてよく用いられるのは、「たい焼き器」と「たい焼き」です。

クラスとインスタンスの具体例

1つのたい焼き器(クラス)によって、見た目が同じ形のたい焼き(インスタンス)をどんどん作ることができます。

もちろん材料を入れることで、たい焼き毎に中身の味を変えられます。

インスタンス生成

たい焼きの見た目が同じ形でも、たい焼き(インスタンス)ごとに「味」や「値段」といった中身が異なる情報を持たせることができます。

この辺りは実際のソースコードをみた方が理解しやすいので、順を追って説明します。

用語を一旦整理してみよう

ここまで出てきた用語を整理してみましょう。

用語 説明
プログラミング プログラムを作ること
プログラム コンピュータに作業させる一連の手順を記述したもの
プログラミング言語 コンピュータが理解できる機械語に翻訳しやすい言葉
オブジェクト指向
プログラミング
ものを組み立てるように表現するプログラムの記述手法
オブジェクト Rubyで扱うことができる全てのデータ
振る舞い(動作) メソッドのこと
状態 オブジェクト毎のデータのこと
クラス オブジェクトの設計図に相当するもの
オブジェクトの振る舞いや状態を定義する
インスタンス クラスの定義に基づいて生成されるオブジェクトの実物体
ぴっかちゃん

たくさんあって覚えられるかなぁ。。。

このあと何回も出てくるから、いま覚える必要はないよ!

ぴかわかさん

クラスとインスタンスを作ってみよう

それでは、実際にコードをみながらクラスとインスタンスを作ってみましょう。

クラスとインスタンスの具体例

taiyaki.rbという名前のファイルを用意しておきましょう。

クラスを定義しよう

新しいクラスを定義するには、キーワードのclassを使います。

クラスの定義
1
2
class クラス名
end

それでは、たい焼きの設計図である「Taiyakiクラス」を定義してみましょう。
以下のソースコードを「taiyaki.rb」に書いてみましょう。

taiyaki.rb | Taiyakiクラスを定義する
1
2
class Taiyaki
end

クラスには、クラス名の先頭は大文字にするという決まりがあるので、taiyakiではなくTaiyakiと書きます。

ポイント
  1. クラスは、オブジェクトの設計図に相当するもの
  2. クラス名の先頭には、大文字を使う

インスタンスを生成しよう

インスタンスを生成するには、クラスに対して「newメソッド」を呼び出します。

クラスのインスタンスを生成する
1
クラス名.new

それでは、たい焼きの設計図であるTaiyakiクラスから「たい焼き」を作ってみましょう。
以下のようにTaiyaki.newを「taiyaki.rb」に書いてみましょう。

taiyaki.rb | たい焼きの設計図からたい焼きを作成する
1
2
3
4
class Taiyaki
end

Taiyaki.new

以下のようにTaiyaki.newによって「Taiyakiクラスのインスタンス」が生成されます。

Taiyakiクラスのインスタンス

また、たい焼き器からいくつでもたい焼きを作れるように、クラスからは1つのインスタンスだけではなく、newメソッドを繰り返し呼び出すことで、複数のインスタンスを生成することができます。

ポイント

クラスに対してnewメソッドを呼び出すと、そのクラスのインスタンスを生成することができる。

initializeメソッド

インスタンス生成したときに実行したい処理があれば、クラスの中に「initializeメソッド」という特殊なメソッドを定義しておきます。initializeメソッドとは、newメソッドでインスタンスを生成した際に自動で呼ばれるメソッドのことです。

initializeメソッドは、以下のようにクラスの中に定義します。

initializeメソッドの定義
1
2
3
4
5
class クラス名
def initialize
#インスタンス生成時に実行したい処理を書く
end
end

それでは、Taiyakiクラスにinitializeメソッドを定義して、インスタンス生成時に自動で呼び出されることを確認してみましょう。

以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | initializeメソッドを定義する
1
2
3
4
5
6
7
class Taiyaki
def initialize
puts "initializeメソッドが実行されました。"
end
end Taiyaki.new

動画のようにtaiyaki.rbを実行すると、ターミナルにはinitializeメソッドが実行されましたと出力されます。

 initializeメソッドの動作を確認

前回の章では「メソッドを実行するには『メソッド呼び出し』が必要」と学びましたね。

しかし今回はTaiyaki.newが実行されると、initializeメソッドが自動で呼び出されるので、以下のような動作になります。

initializeメソッドの動作

初学者の方がよく混乱してしまうのが「newメソッド」と「initializeメソッド」だよ。2つのメソッドの違いをしっかりおさえておこう!

ぴかわかさん
ぴっかちゃん

newメソッドは「クラスのインスタンスを生成する」だよ。initializeメソッドは「newメソッドが実行されると自動で呼び出される」だよね!

initializeメソッドで引数を使う場合

initializeメソッドへの引数の指定は、以下のようにnewメソッドの引数で指定します。

引数を使う場合
1
2
3
4
5
6
7
class クラス名
def initialize(仮引数)
#インスタンス生成時に実行したい処理を書く end end
クラス名.new(実引数)

それでは、initializeメソッドへの引数を指定して、インスタンス生成後にたい焼きの「味」と「値段」をターミナルへ出力できるようにしてみましょう。

以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | initializeメソッドに引数を使う
1
2
3
4
5
6
7
class Taiyaki
def initialize(taste, price)
puts "#{taste}味のたい焼きは、#{price}円です。"
end end
Taiyaki.new("あんこ", 250)

動画のようにtaiyaki.rbを実行すると、あんこ味のたい焼きは、250円と出力されます。

initializeメソッドに引数を使う

newメソッドに指定した実引数("あんこ", 250)は、以下のようにinitializeメソッドで指定する仮引数(taste, price)へそれぞれ渡されます。

initializeメソッドの中で仮引数を使うことで、渡された値を参照することができます。

initializeメソッドの引数を使う場合の動作

次のインスタンス変数で詳しく説明しますが、本来initializeメソッドはインスタンスの初期化の設定を行うことが望ましいです。

今回はinitializeメソッドの引数を説明するために、上記のような使い方をしています。

ポイント
  1. クラスのインスタンスを生成する場合は、newメソッドを使う
  2. newメソッドを呼び出すと、自動的にinitializeメソッドが呼び出される
  3. newメソッドで指定した引数は、initializeメソッドに渡される

空のクラスとインスタンス

newメソッドは、指定したクラスのインスタンスを生成して返します。

Taiyakiクラスのインスタンスは、#<Taiyaki:0x00000000014580e8>のような形式で表現されます。数値の部分はインスタンスごとに異なります。

サンプルコード | newメソッドの戻り値を確認する
1
2
3
4
5
class Taiyaki
end

Taiyaki.new
#=> #<Taiyaki:0x00000000014580e8>

上記のTaiyakiクラスのように、設計図に何も書いていない状態でTaiyaki.newしても、見た目はたい焼きの形だけど皮しかないたい焼き、つまり何も情報をもたないインスタンスが作られるだけです。

何も情報をもたないたい焼き

このままでは、たい焼きの「味」や「値段」が分かりません。
たい焼き(インスタンス)に情報をもたせるには、「インスタンス変数」を使います。

ポイント
  1. newメソッドは、指定したクラスのインスタンスを生成して返す
  2. クラスの中身が空の状態だと、何も情報をもたないインスタンスが生成される

インスタンス変数について学ぼう

インスタンス変数とは、名前の先頭に@がついた変数のことです。

サンプルコード | インスタンス変数に値を代入する
1
@taste = "あんこ"

initializeメソッドの中でインスタンス変数を初期化することで、インスタンス生成時に情報をもたせることができます。

サンプルコード | initializeメソッドの中でインスタンス変数を初期化する
1
2
3
4
5
class クラス名
  def initialize
@taste = "あんこ"
end end

たい焼きを作るときに「味」の情報をもたせたい場合は、以下のようにinitializeメソッドの中で@tasteというインスタンス変数を引数を使って初期化します。

引数を使うことで、固定ではなく味を変えてたい焼きを作ることができます。

サンプルコード | 引数を使ってインスタンス変数を初期化する
1
2
3
4
5
6
7
8
class Taiyaki
def initialize(taste)
@taste = taste #@tasteには、引数に渡された値が代入される
end end #newメソッドの引数に指定した値は、initializeメソッドの引数に渡される
Taiyaki.new(@tasteに代入する値を指定する)
ポイント
  1. インスタンス変数とは、名前の先頭に@がついた変数のこと
  2. initializeメソッドでは、インスタンス変数の初期化を行う

あんこ味のたい焼きを作ることを考えてみよう

例として、あんこ味のたい焼きを作ることを考えてみましょう。

インスタンス変数の@tasteに代入したい値は"あんこ"になるので、以下のようにnewメソッドの引数には"あんこ"を指定します。

サンプルコード | あんこ味のたい焼きを作る
1
2
3
4
5
6
7
8
class Taiyaki
  def initialize(taste)
    @taste = taste
  end
end

Taiyaki.new("あんこ")
# => #<Taiyaki:0x0000000002dbf518 @taste="あんこ"> #生成されたインスタンス

Taiyaki.new("あんこ")によって生成されたインスタンスを確認すると、数値のあとには@taste="あんこ"が設定されていますね。

このインスタンスには、たい焼きの「味はあんこ」という情報があります。

あんこ味のたい焼き

このようにinitializeメソッドでインスタンス変数を初期化すると、インスタンス生成時に何かしらの情報を持たせることができます。

実際に手を動かしながら、インスタンスが情報を持てるようにしよう!

ぴかわかさん

インスタンス変数を定義しよう

それでは、たい焼きを作るときに「味」や「値段」の情報をもてるように、Taiyakiクラスのinitializeメソッドの中にインスタンス変数を定義してみましょう。

以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | たい焼き作成時に味と値段の情報をもてるようにする
1
2
3
4
5
6
7
8
class Taiyaki
  def initialize(taste, price)
@taste = taste
@price = price
end end
p Taiyaki.new("あんこ", 250)

動画のようにtaiyaki.rbを実行すると、生成されたインスタンスが出力されます。
※数値の部分はインスタンス毎に異なるので、一致している必要はありません

インスタンス変数を使う

処理の流れを1つ1つ確認してみましょう。

newメソッドに指定した実引数("あんこ", 250)は、initializeメソッドで指定する仮引数(taste, price)へ渡され、インスタンス変数@taste@priceにそれぞれ代入されます。

インスタンス変数に値を代入する

続いて、以下のようにTaiyakiクラスのインスタンスが戻り値として呼び出し元に返ります。

newメソッドの戻り値

処理の流れを整理
  1. newメソッドの実引数の値は、initializeメソッドの仮引数に渡される
  2. 仮引数の値は、それぞれのインスタンス変数に代入される
  3. 生成されたインスタンスには、インスタンス変数によって値が保持される

空のクラスと比べてみよう

中身が空のクラスに対してインスタンス生成した場合と比べてみます。

クラスに何も書かれていない状態では、以下のようにTaiyaki.newしても何も情報をもたないインスタンスが生成されるだけでしたね。

空のクラスからインスタンス生成する

しかし、クラスのinitializeメソッドの中でインスタンス変数を初期化すれば、生成するインスタンスに情報を持たせることできます。

今回は@taste@priceを使って、味と値段の情報をインスタンス毎に持たせます。

味と値段の情報をインスタンス毎に持たせる

このようにインスタンスに何か情報を持たせたい場合は、インスタンス変数を使います。

インスタンス変数の特徴として、他にも「クラス内の異なるメソッド間でも値を受け渡せる」「インスタンス毎に固有の値を保持できる」などがあります。

この特徴は、次のインスタンスメソッドを学ぶことによって理解することができます。

ポイント
  1. 中身が空のクラスの場合は、情報をもたないインスタンスが生成される
  2. インスタンス変数を使うと、インスタンスに値を保持できるようになる
  3. initializeメソッドの中でインスタンス変数を初期化すれば、インスタンス生成時に値を設定することができる
次に進む前に必要のない処理を削除しよう

taiyaki.rbのソースコードを編集しましょう。

pメソッドは削除して、変数のanko_taiyakiTaiyaki.new("あんこ", 250)を代入しておきましょう。

taiyaki.rb | 変数に代入する
1
2
3
4
5
6
7
8
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end
end

anko_taiyaki = Taiyaki.new("あんこ", 250)

newメソッドによって生成されたTaiyakiクラスのインスタンスは、繰り返し利用できるように変数のanko_taiyakiに代入しておきます。

インスタンスメソッドを定義しよう

インスタンスメソッドとは、クラスのインスタンスに対して呼び出すことができるメソッドのことです。クラスの中でキーワードのdefを使って普通に定義したメソッドは、インスタンスメソッドとして扱われます。

インスタンスメソッドを定義する
1
2
3
4
5
class クラス名
def メソッド名
# 処理
end
end

インスタンスメソッドの呼び出しは、以下のように対象のインスタンスにドット(.)をつなげてメソッド名を指定します。

インスタンスメソッドの呼び出し
1
対象のインスタンス.メソッド名

それでは、Taiyakiクラスにインスタンスメソッドを定義していきましょう。

インスタンスメソッドと共にインスタンス変数の特徴も学んでいくよ!

ぴかわかさん
ぴっかちゃん

たしかインスタンス変数の特徴は「クラス内の異なるメソッド間でも値を受け渡せる」「インスタンス毎に異なる値を扱える」だったね

インスタンス変数を使って処理を書いてみよう

インスタンス変数は、クラス内の異なるメソッド間でも値を受け渡せる」ので、インスタンスメソッドの中でもインスタンス変数を利用することができます。

以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | インスタンスメソッドのshow_infoを定義する
1
2
3
4
5
6
7
8
9
10
11
12
13
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

def show_info
puts "#{@taste}味のたい焼きは#{@price}円です。"
end
end anko_taiyaki = Taiyaki.new("あんこ", 250)
anko_taiyaki.show_info

show_infoはインスタンス変数の@taste@priceを利用して、インスタンスの保持するたい焼きの味や値段を表示するインスタンスメソッドです。

動画のようにtaiyaki.rbを実行すると、あんこ味のたい焼きは250円と出力されます。

インスタンスメソッドを呼び出す

anko_taiyakiには、以下のように@taste@price"あんこ"250が設定されたTaiyakiクラスのインスタンスが代入されています。

anko_taiyakiに代入されるインスタンス

このインスタンスが持つ情報は、インスタンス変数を使うことでクラス内の異なるメソッド間でも扱うことができます。

以下のようにanko_taiyakiに対してshow_infoメソッドを呼び出すと、show_infoメソッド内のインスタンス変数は、anko_taiyakiが持つ値をそれぞれ参照します。

インスタンスメソッドを呼び出す流れ

このようにインスタンスメソッドの中でインスタンス変数を使うと、対象のインスタンスが持つ情報を利用することができます。

インスタンスが保持している情報は、クラス内の異なるメソッドでも共有できます。

ポイント
  1. インスタンス変数は、クラス内の異なるメソッド間でも値を受け渡せる
  2. インスタンスメソッドの中でインスタンス変数を使うと、インスタンスが持つ情報を利用できる

インスタンス毎に保持される情報を確かめてみよう

インスタンス変数は、インスタンス毎に異なる値を扱うことができます。

先ほどのanko_taiyakiには、@taste = "あんこ" @price = 250の情報をもつTaiyakiクラスのインスタンスが代入されていますね。

anko_taiyakiに代入されるインスタンス
1
2
anko_taiyaki = Taiyaki.new("あんこ", 250)
# => #<Taiyaki:0x00000000026b4840 @taste="あんこ", @price=250>

anko_taiyakiに代入されるインスタンス

これはインスタンス生成時に、newメソッドの引数の値でインスタンス変数を初期化しているからでしたね。

以下のようにnewメソッドの引数に"あんこ"250を指定しています。

サンプルコード | インスタンス変数の初期化
1
2
3
4
5
6
7
8
9
10
class Taiyaki
def initialize(taste, price)
@taste = taste
@price = price
end
#...以下省略 end #インスタンス変数に代入する値は、newメソッドの引数に指定
anko_taiyaki = Taiyaki.new("あんこ", 250)

newメソッドの引数に指定する値を変更すると、インスタンス変数に"あんこ"250とは異なる情報を設定することができます。

例として、「カスタード味のたい焼き 300円」で考えてみましょう。

newメソッドの引数に"カスタード"300を指定することで、@taste = "カスタード" @price = 300の情報をもつTaiyakiクラスのインスタンスが生成されます。

custard_taiyakiに代入されるインスタンス
1
2
custard_taiyaki = Taiyaki.new("カスタード", 300)
# => #<Taiyaki:0x00000000009ef980 @taste="カスタード", @price=300

custard_taiyakiには、この情報を持つインスタンスが代入されます。

カスタード味のたい焼き

このようにインスタンス変数は、インスタンス毎に異なる値を保持することができます。

インスタンス毎にインスタンスメソッドを呼び出してみよう

anko_taiyakiに対してshow_infoメソッドを呼び出した場合は、「あんこ味のたい焼きは250円です。」と出力されましたね。

anko_taiyakiに対して、show_infoメソッドを呼び出す
1
2
3
4
anko_taiyaki.show_info
# 出力結果 あんこ味のたい焼きは250円です。

それではcustard_taiyakiに対してshow_infoメソッドを呼び出すと、どのような結果になるでしょうか。

インスタンス毎にインスタンスメソッドを呼び出す

実際にカスタード味のたい焼きを作成して確かめてみましょう。
以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | カスタード味のたい焼きを作成する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

  def show_info
    puts "#{@taste}味のたい焼きは#{@price}円です。"
  end
end

anko_taiyaki = Taiyaki.new("あんこ", 250)
anko_taiyaki.show_info

custard_taiyaki = Taiyaki.new("カスタード", 300)
custard_taiyaki.show_info

custard_taiyakiに対してshow_infoメソッドを呼び出した場合は、動画のように「カスタード味のたい焼きは300円です。」と出力されます。

custard_taiyakiに対してインスタンスメソッド呼び出し

anko_taiyaki.show_infoの出力結果とは違いますよね。

出力結果

インスタンスメソッドは、インスタンス毎に異なる処理を行うことができます。それはインスタンス変数によって、インスタンス毎に異なる情報を持っているからです。

以下のようにanko_taiyakiに対してshow_infoを呼び出せば、インスタンスメソッドであるshow_infoのインスタンス変数は"あんこ"250をそれぞれ参照します。

ソースコード1

custard_taiyakiに対してshow_infoを呼び出した場合は、以下のようにインスタンス変数はそれぞれ"カスタード"300を参照します。

ソースコード2

このようにインスタンス変数は、生成されたインスタンス毎に共有される変数です。

インスタンス変数

ポイント
  1. インスタンスメソッドは、クラスのインスタンスに対して呼び出せるメソッド
  2. インスタンス変数は、インスタンス毎に異なる値を保持することができる
次に進む前に必要のない処理をコメントアウトしよう

taiyaki.rbのソースコードを編集しましょう。

次のアクセサメソッドではshow_infoは使わないので、以下のように3行をコメントアウトしておきましょう。

taiyaki.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

  def show_info
    puts "#{@taste}味のたい焼きは#{@price}円です。"
  end
end

anko_taiyaki = Taiyaki.new("あんこ", 250)
#anko_taiyaki.show_info
#custard_taiyaki = Taiyaki.new("カスタード", 300)
#custard_taiyaki.show_info

アクセサメソッドについて学ぼう

Rubyでは、クラス外部からインスタンス変数に対して直接操作することができません。

以下のようにクラス外部から@tasteを参照したり、変更を行おうとすると、エラーが発生してしまいます。

インスタンス変数をクラス外部から参照した場合
1
2
3
4
5
6
7
8
9
10
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end
end

anko_taiyaki = Taiyaki.new("あんこ", 250)
anko_taiyaki.@taste
#taiyaki.rb:9: syntax error, unexpected instance variable anko_taiyaki.@taste
インスタンス変数をクラス外部から変更した場合
1
2
anko_taiyaki.@taste = "栗あん"
# taiyaki.rb:11: syntax error, unexpected instance variable anko_taiyaki.@taste = "栗あん"

クラスの外部からインスタンス変数を参照・変更するには、それを目的としたインスタンスメソッドを定義する必要があります。

ゲッターメソッド

クラスの外部からインスタンス変数の値を参照するインスタンスメソッドのことを「ゲッターメソッド」と呼びます。

ゲッターメソッド名は、それぞれ@なしのインスタンス変数名を付けます。

クラスの外部から@tasteの値を参照するには、以下のようにゲッターメソッドのtasteを定義し、呼び出します。

ゲッターメソッドを経由して@tasteの値を参照する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

  #ゲッターメソッド(@tasteを外部から参照するためのメソッド)
def taste
@taste #"あんこ"を呼び出し元へ返す
end
end anko_taiyaki = Taiyaki.new("あんこ", 250)
anko_taiyaki.taste #=> "あんこ"

インスタンス変数は「クラス内の異なるメソッド間でも値を受け渡せる」と学びましたね。

上記ではanko_taiyakiに対してtasteを呼び出しているので、tasteメソッド内の@tasteでは"あんこ"を参照することができます。

ぴっかちゃん

ゲッターメソッドを経由してインスタンス変数の値を参照できるんだね!

セッターメソッド

インスタンス変数の値をクラスの外部から変更するためのインスタンスメソッドのことを「セッターメソッド」と呼びます。

セッターメソッド名は、@なしのインスタンス変数名で末尾に=をつけます。

クラスの外部から@tasteの値を変更するには、セッターメソッドのtaste=を以下のように定義し、呼び出します。

セッターメソッドを経由して@tasteの値を変更する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

  #セッターメソッド(@tasteを外部から変更するためのメソッド)
def taste=(taste)
@taste = taste
end
end anko_taiyaki = Taiyaki.new("あんこ", 250)
anko_taiyaki.taste = "栗あん"
#変更されたか確認する anko_taiyaki.taste #=> "栗あん"

上記のanko_taiyaki.taste = "栗あん"では、anko_taiyaki.taste"栗あん"を代入しているようにみえますよね。

実際には、以下のように引数に"栗あん"を指定してtaste=を呼び出しています。

サンプルコード
1
2
3
4
5
#代入しているようにみえるが...
anko_taiyaki.taste = "栗あん"

#実際にはtaste=メソッドを呼び出している
anko_taiyaki.taste=("栗あん")

セッターメソッドのtaste=のように、メソッド名の末尾に=(イコール)をつけると、代入式のようにメソッドを呼び出すことができます。

ぴっかちゃん

セッターメソッドを経由してインスタンス変数の値が変更できるんだね!

実際に手を動かして、ゲッター / セッターメソッドを定義してみよう

ぴかわかさん

ゲッターメソッド / セッターメソッドを定義してみよう

まずは、クラスの外部から@taste@priceの値を参照できるようにゲッターメソッドを定義しましょう。

以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | ゲッターメソッドを定義して@tasteと@priceの値を参照する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

def taste
@taste
end
def price
@price
end
def show_info puts "#{@taste}味のたい焼きは#{@price}円です。" end end anko_taiyaki = Taiyaki.new("あんこ", 250)
p anko_taiyaki.taste
p anko_taiyaki.price
#anko_taiyaki.show_info #custard_taiyaki = Taiyaki.new("カスタード", 300) #custard_taiyaki.show_info

taiyaki.rbを実行すると、動画のように"あんこ"250がターミナルへ出力されます。

ゲッターメソッド

ゲッターメソッドのtastepriceによって、各インスタンス変数の値を参照できるようになりましたね。

ぴかわかさん

続いて、クラスの外部から@taste@priceの値を変更できるようにセッターメソッドを定義しましょう。

anko_taiyakiがもつ各インスタンス変数の値を"栗あん"350に変更できるように、以下のソースコードをtaiyaki.rbに書き、rubyコマンドで実行してみましょう。

taiyaki.rb | セッターメソッドを定義して@tasteと@priceの値を変更する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

  def taste
    @taste
  end

  def price
    @price
  end

def taste=(taste)
@taste = taste
end
def price=(price)
@price = price
end
def show_info puts "#{@taste}味のたい焼きは#{@price}円です。" end end anko_taiyaki = Taiyaki.new("あんこ", 250) p anko_taiyaki.taste p anko_taiyaki.price
anko_taiyaki.taste = "栗あん"
anko_taiyaki.price = 350
p anko_taiyaki.taste
p anko_taiyaki.price
#anko_taiyaki.show_info #custard_taiyaki = Taiyaki.new("カスタード", 300) #custard_taiyaki.show_info

taiyaki.rbを実行すると、動画のように"あんこ"250の後に変更された "栗あん"350がターミナルに出力されます。

セッターメソッド

セッターメソッドであるtaste=price=によって、各インスタンス変数の値を変更できるようになりましたね。

ポイント
  1. Rubyでは、クラス外部からインスタンス変数に対して直接操作することができないので、ゲッター / セッターメソッドを経由する必要がある
  2. ゲッターメソッドは、インスタンス変数の読み取り用のインスタンスメソッド
  3. セッターメソッド、インスタンス変数の書き込み用のインスタンスメソッド

attr_accessorメソッド

ゲッターメソッドとセッターメソッドは、参照・変更したいインスタンス変数が増える度に定義する必要があるので、コード量が増えてしまいます。そこで「attr_accessorメソッド」を使うことで、まとめてアクセサメソッドを定義することができます。

attr_accessorメソッドとは、ゲッター / セッターメソッドを自動で定義してくれるメソッドのことです。

以下のように参照と変更したいインスタンス変数名をシンボル、もしくは文字列で指定します。カリキュラムでは、シンボルの指定方法で進めます。

attr_accessorメソッドの書き方
1
attr_accessor :インスタンス変数名

クラスの外部から@ageを参照・変更できるようにしたい場合は、以下のようにクラスの中に定義します。

サンプルコード
1
2
3
def クラス名
  attr_accessor :age #インスタンス変数名は@なしで指定する
end

上記によって自動で定義されるゲッター / セッターメソッドは、以下の通りです。

attr_accessor :ageによって自動で定義されるメソッド
1
2
3
4
5
6
7
8
9
# ゲッターメソッド
def age
  @age
end

# セッターメソッド
def age=(age)
  @age = age
end

複数行にかけて定義していたメソッドが1行で済むので、コードもスッキリとしますね。

これまでTaiyakiクラスでは、@taste@priceのゲッター / セッターメソッドをそれぞれ定義しているので、以下のように冗長なソースコードになっています。

taiyaki.rb | attr_accessorメソッド使用前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Taiyaki
  def initialize(taste, price)
    @taste = taste
    @price = price
  end

  def taste
    @taste
  end

  def price
    @price
  end

  def taste=(taste)
    @taste = taste
  end

  def price=(price)
    @price = price
  end

  def show_info
    puts "#{@taste}味のたい焼きは#{@price}円です。"
  end
end

anko_taiyaki = Taiyaki.new("あんこ", 250)
p anko_taiyaki.taste
p anko_taiyaki.price

anko_taiyaki.taste = "栗あん"
anko_taiyaki.price = 350

p anko_taiyaki.taste
p anko_taiyaki.price

#anko_taiyaki.show_info

#custard_taiyaki = Taiyaki.new("カスタード", 300)
#custard_taiyaki.show_info

attr_accessorメソッドで、Taiyakiクラスの中をスッキリさせよう!

ぴかわかさん

taiyaki.rbを以下のソースコードのように編集しましょう。

クラスの外部から参照・変更したいインスタンス変数は、@taste@priceの2つあるので、attr_accessorメソッドに指定する際にカンマ(,)で区切ります。

taiyaki.rb | attr_accessorメソッドを使う
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Taiyaki
attr_accessor :taste, :price
def initialize(taste, price) @taste = taste @price = price end def show_info puts "#{@taste}味のたい焼きは#{@price}円です。" end end anko_taiyaki = Taiyaki.new("あんこ", 250) p anko_taiyaki.taste p anko_taiyaki.price anko_taiyaki.taste = "栗あん" anko_taiyaki.price = 350 p anko_taiyaki.taste p anko_taiyaki.price #anko_taiyaki.show_info #custard_taiyaki = Taiyaki.new("カスタード", 300) #custard_taiyaki.show_info

attr_accessorメソッドを使うことで、Taiyakiクラスのコード量がずいぶんと減りましたね。

最後に問題なく動くかどうかを確かめるために、taiyaki.rbを実行してみましょう。

attr_accessorメソッドを使う

動画のようにターミナルに出力されたら問題ありません。

ポイント
  1. attr_accessorメソッドとは、ゲッター / セッターメソッドを自動で定義してくれるメソッドのこと
  2. 参照と変更したいインスタンス変数名をシンボル、もしくは文字列で指定する

クラス変数を定義しよう

クラス変数とは、名前の先頭に@が2つ付いた変数のことです。

サンプルコード | クラス変数に値を代入する
1
@@name = "ぴっかちゃん"

クラス変数には、全てのインスタンスで共有される共通の情報をもたせることができます。

インスタンス変数は「生成されたインスタンス毎に共有される変数」だったのに対して、クラス変数は「全てのインスタンスで共有される変数」です。

全てのインスタンスで共有される変数

たい焼きが全部で何個作られたかわかるように、クラス変数を定義してみましょう。

以下のソースコードのようにtaiyaki.rbにクラス変数の@@total_taiyaki_countを定義して、たい焼きを作る度にカウントアップさせましょう。

taiyaki.rb | クラスの定義部分
1
2
3
4
5
6
7
8
9
10
11
12
class Taiyaki
  attr_accessor :taste, :price

@@total_taiyaki_count = 0
def initialize(taste, price) @taste = taste @price = price
@@total_taiyaki_count += 1
end #...以下省略 end

上記では、Taiyaki クラスの中で@@total_taiyaki_count0で初期化し、initializeメソッドで@@total_taiyaki_countの値をひとつ加算しています。

initializeメソッドは、newメソッドを呼び出すと自動で呼び出されるメソッドでしたね。

つまり、newメソッドでTaiyakiクラスのインスタンスを生成する(たい焼きを作成する)度に@@total_taiyaki_countの値がひとつ加算されます。

次のクラスメソッドで、たい焼きが全部で何個作られたかを確認するよ

ぴかわかさん
ポイント
  1. クラス変数とは、名前の先頭に@が2つ付いた変数のこと
  2. 全てのインスタンスで共有される共通の情報をもたせることができる
  3. インスタンス変数はインスタンス毎、クラス変数は全てのインスタンスで共有される違いがある

クラスメソッドを定義しよう

同じクラスから生成されるインスタンスが共通で使用する処理は、クラスの中に「クラスメソッド」というメソッドを定義します。クラスメソッドとは、クラスに対して呼び出すことができるメソッドのことです。

クラスメソッドは、2つの定義方法があります。

クラスメソッドの定義方法1
1
2
3
4
5
class
def self.クラスメソッド名
# 処理
end
end
クラスメソッドの定義方法2
1
2
3
4
5
6
7
class クラス名  
class << self
def クラスメソッド名
# 処理
end
end
end

クラスメソッドの定義は、どちらの方法でも構いませんが、クラスメソッドをたくさん定義する場合は、定義方法2の方がクラスメソッド名に毎回self.と付けなくてよいです。

クラスメソッドの呼び出しは、対象のクラスにドット(.)をつなげてクラスメソッド名を指定します。

クラスメソッドの呼び出し
1
クラス名.クラスメソッド名

例としてHello!と挨拶するHelloクラスのクラスメソッドであるgreetingを定義し、呼び出すには以下のように書きます。

サンプルコード | 定義方法1でクラスメソッドを定義する
1
2
3
4
5
6
7
8
9
class Hello
  # クラスメソッドを定義
  def self. greeting
    puts "Hello!"
  end
end

# クラスメソッドを呼び出す
Hello.greeting #=> Hello!

クラス変数を使って処理を書いてみよう

それでは、たい焼きが全部で何個作られたかを案内してくれるクラスメソッドのshow_all_countを定義してみましょう。

たい焼きが作成された個数は、先ほど学んだクラス変数の@@total_taiyaki_countが保持しています。以下のようにtaiyaki.rbにクラスメソッドを追加しましょう。

taiyaki.rb | クラスの定義部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Taiyaki
  attr_accessor :taste, :price

  @@total_taiyaki_count = 0

  def initialize(taste, price)
    @taste = taste
    @price = price
    @@total_taiyaki_count += 1
  end

  def show_info
    puts "#{@taste}味のたい焼きは#{@price}円です。"
  end

def self.show_all_count
puts "たい焼きは全部で#{@@total_taiyaki_count}個作成されました。"
end
end

続いて、Taiyakiクラス外でnewメソッドを呼び出してインスタンスを生成し、クラスメソッドを呼び出してみましょう。

Taiyakiクラス外の処理は一旦全てコメントアウトして、以下の内容を追加しましょう。

taiyaki.rb | Taiyakiクラス外に処理を書く
1
2
3
4
5
Taiyaki.new("あんこ", 250)
Taiyaki.new("カスタード", 300)
Taiyaki.new("抹茶", 350)

Taiyaki.show_all_count

動画のようにrubyコマンドでtaiyaki.rbを実行してみましょう。

たい焼きが全部で何個作成したかを確かめる

newメソッドによってTaiyakiクラスのインスタンスを全部で3つ生成したので、ターミナルにはたい焼きは全部で3個作成されました。と出力されます。

このようにクラスメソッドにクラス変数を使うことで、同じクラスのインスタンスで共有する情報の処理を行えます。

ポイント
  1. クラスメソッドとは、クラスに対して呼び出すことができるメソッドのこと
  2. 同じクラスから生成されるインスタンスが共通で使用する処理に使う
  3. インスタンスメソッドは、インスタンス毎に保持されるデータ(インスタンス変数)の処理に使う

完成したtaiyaki.rbのソースコード

お疲れ様でした!これで「クラスとインスタンス」は終了です。完成のtaiyaki.rbのソースコードをコメントアウトの解説付きで載せておきますので、比較して確認してみてください。

taiyaki.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#たい焼きの設計図を作成
class Taiyaki

  #@tasteと@priceのゲッター・セッターメソッドを定義(クラス外から参照・変更可能になる)
  attr_accessor :taste, :price

  #クラス変数を0で初期化
  @@total_taiyaki_count = 0

  #newメソッドでインスタンスを生成した際に自動で呼ばれるメソッド
  def initialize(taste, price)
    #インスタンス変数を引数の値で初期化
    @taste = taste
    @price = price

    #クラス変数の値をひとつ加算させる
    @@total_taiyaki_count += 1
  end

  #インスタンスメソッド
  def show_info
    puts "#{@taste}味のたい焼きは#{@price}円です。"
  end

  #クラスメソッド
  def self.show_all_count
    puts "たい焼きは全部で#{@@total_taiyaki_count}個作成されました。"
  end
end

#Taiyakiクラスの外

#Taiyakiクラスのインスタンスを生成
anko_taiyaki = Taiyaki.new("あんこ", 250)

#クラスの外からanko_taiyakiが保持する@tasteと@priceの値を参照
p anko_taiyaki.taste
p anko_taiyaki.price

#クラスの外からanko_taiyakiが保持する@tasteと@priceの値を変更
anko_taiyaki.taste = "栗あん"
anko_taiyaki.price = 350

#クラスの外からanko_taiyakiが保持する@tasteと@priceの値を参照(変更できたか確認)
p anko_taiyaki.taste
p anko_taiyaki.price

#anko_taiyakiに対してインスタンスメソッド呼び出し
anko_taiyaki.show_info

#Taiyakiクラスのインスタンスを生成
custard_taiyaki = Taiyaki.new("カスタード", 300)

#custard_taiyakiに対してインスタンスメソッド呼び出し
custard_taiyaki.show_info

#クラスメソッド呼び出し
Taiyaki.show_all_count

※「クラス変数を使って処理を書いてみよう」で追加したコードは、以下のようにハイライト箇所を不要なため削除してあります。

「クラス変数を使って処理を書いてみよう」で追加したコード
1
2
3
4
5
Taiyaki.new("あんこ", 250)
Taiyaki.new("カスタード", 300)
Taiyaki.new("抹茶", 350)
Taiyaki.show_all_count

最後にこれまで出てきた用語を整理していこう

ぴかわかさん

オブジェクト指向プログラミングの用語整理

ここまでたくさんの用語が出てきましたが、1つ1つ整理してみましょう。

用語 意味/役割
クラス オブジェクト指向における設計図
インスタンス クラスから生成された実物体
インスタンス変数
@変数名
インスタンス毎に値を保持できる
クラス変数
@@変数名
クラス内の全てのインスタンスで共有される値
インスタンスメソッド インスタンスに対する操作を行うためのメソッド
クラスメソッド クラスに対する操作を行うためのメソッド
initializeメソッド 主にインスタンスの初期化の設定を行うためのメソッド
ゲッターメソッド クラスの外部からインスタンス変数の値を参照するインスタンスメソッド
セッターメソッド インスタンス変数の値をクラスの外部から変更するためのインスタンスメソッド
attr_accessorメソッド ゲッター / セッターメソッドを自動で定義してくれるメソッド
アクセサメソッド インスタンス変数の参照と変更ができるメソッドの総称

この記事のまとめ

  • クラスには、設計図としてオブジェクトの振る舞いや状態を設定できる
  • インスタンスは、クラスに基づいて生成されたオブジェクトのこと
  • クラスに対してnewメソッドを呼び出すと、インスタンス生成できる