hiyoko-programingの日記

プログラミングを勉強したてのひよっ子。   エンジニア目指して勉強中。

クラスとインスタンスのコード理解

Rubyのオブジェクトは、全ていずれかのクラスのインスタンスである。
例えば、今まで使っていた"Hello World"のような文字列はStringクラスのインスタンス

[例]Stringクラス
1
2
  string1 = "Hello World"     # インスタンス
  string2 = "こんにちは Ruby"  # インスタンス

この"Hello World"と"こんにちは"は、それぞれ文字列のオブジェクト。もちろん中身の文字は違うが、文字を持つということは共通している
さらに、文字列のオブジェクトであれば、以下のように共通のメソッドが使用できる

[例]Stringクラス
1
2
3
4
5
6
  string1 = "Hello World"
  string2 = "こんにちは"

  # どちらもlengthメソッドが使える
  puts string1.length
  puts string2.length

https://tech-master.s3.amazonaws.com/uploads/curriculums//9f1edc3f3214a6f31de6130e1576f8ae.png

これまで文字列は使用していても、Stringクラスなどというクラスを定義したことはないはず。
実は、Rubyにはあらかじめ定義されているクラスが存在する。今とりあげたStringクラスを始め、配列オブジェクトのArrayクラス、数値オブジェクトのIntegerクラス、ハッシュオブジェクトのHashクラスなど。

ここまでのカリキュラムで書いてきたコードで使用したオブジェクトは、全て、このようなあらかじめ定義されているクラスのインスタンス。そして、これらのクラスに定義されたメソッドを使用。

Rubyでオブジェクトを生成するときは、必ずクラスを定義して、そのクラスに基いてインスタンスを生成するという作業が必要。

文字列や数値などのよく使うであろうオブジェクトを、エンジニアがコードを書くたびにいちいちクラスから定義していたら相当な手間がかかる。そのため、こうした良く利用されるオブジェクトについてはあらかじめクラスが定義されている(そしてRubyの奥に隠されている)。

要点チェック

 

クラスとインスタンスの実運用

ここからは、実際にコード上でクラスを定義し、インスタンスを生成することでアプリケーションを作成。

これから作るアプリケーションの機能自体は、一つ前のカリキュラムまでで作ったレビュー管理アプリケーション と同じものになる。
ただし、以前作ったものでは、クラスとインスタンスの定義・生成は行わなかった。自分でクラスを定義しなくても、文字列クラス、配列クラス、数値クラス、ハッシュクラスなどのRubyにあらかじめ用意されているクラスとそのインスタンスを組み合わせることで機能を実現していたため。

しかし今回は、アプリケーションで管理するレビューのクラスを定義し、それに基いてレビューのインスタンスを生成して管理していく。

それでは、今回のアプリでどのようなオブジェクトが必要で、そのオブジェクトを扱うためにどのようなクラスとインスタンスを作るべきか。
今回のアプリで使用するオブジェクトはレビュー。レビューはどれもタイトルジャンル感想の三つの属性を持っている。そして、レビューを書くこととレビューを読むことができた。なので、以下のようなクラスとインスタンスの設計になる。

 

  レビュークラス            レビュークラスのインスタンス

共通の属性     共通のメソッド        属性       使えるメソッド

title      書く       →   title:  もののけ姫                    書く

genre      読む             genre: 映画          読む  

impression                                                        impression: 面白い

 

クラスを作る

以下のような属性と処理をもつクラスを実際にコードで表現。

 

レビュークラス(Review)

 属性

   titel: 作品タイトル

          genre: 作品のジャンル

         impression: 作品をみた感想

 

 処理

   レビューを書く

   レビューを読む

   書いたレビュー数を取得する

 

クラスを定義

まずは、クラスを定義する。

クラスの定義
1
2
3
class クラス名
  # 変数/メソッドの定義
end

 クラス名のルール
クラス名は半角英大文字から始める。
例: User Account Image Group など

 sample_class.rbにReviewクラスを定義

Reviewクラスの定義

sample_class.rb
1
2
3
class Review

end

 

インスタンスを生成

定義したクラスからインスタンスを生成する。
インスタンスは、クラスのnewメソッド(定義しなくても利用できる)を実行させることにより生成される。

 

 レビュークラス(Review) →(newメソッド)→ レビュークラスのインスタンス

 

 newメソッド

全てのクラスは、定義しなくてもnewという特別なメソッドを持っている。
このメソッドは、返り値として利用したクラスのインスタンスを返す。

 Reviewクラスのインスタンス、reviewを生成

sample_class.rb
1
2
3
4
5
class Review

end
review = Review.new # Reviewクラスのインスタンスを生成
puts review

このように、クラスの定義と通常のRubyの記述は同じファイル内に書くことができる。
続いて、ターミナルからsample_class.rbを実行。

result
1
  #<Review:0x00XXXXXXXXXX>

上記のように表示されればReviewクラスのインスタンスの生成に成功している。
このあるクラス.newというインスタンス生成のコードは、クラスがメソッドを利用している形。

この段階では、空のクラスを作り、そこからインスタンスを生成しただけ。
なので、クラスが持つ属性(「タイトル」や「ジャンル」)や、各インスタンスが持つ属性値(「もののけ姫」や「映画」)が存在しない。また、クラスのインスタンスが利用できるメソッドも定義されていない。

クラスメソッドとインスタンスメソッド

メソッドの定義の仕方について。
クラスに定義できるメソッドには、クラスメソッドインスタンスメソッドの2種類がある。

 クラスメソッド

クラスが使用できるメソッド。クラスメソッドを定義したクラス自身が使用できる。クラスで共通の情報を使った処理に使用する。

 インスタンスメソッド

インスタンスが使用できるメソッド。インスタンスメソッドを定義したクラスのインスタンスに使用できる。インスタンスごとの個別の情報(属性値)を使った処理に使用する。

レビュー管理アプリケーションのレビュークラスで説明すると以下のようになる。

 

    レビュークラス            レビュークラスのインスタンス

  クラスメソッド               インスタンスメソッド

   新しくインスタンスを作成する        レビューの内容を表示する

    書かれたレビューの総数を表示する  

      ↓                       ↓

   クラスに対して実行           インスタンスに対して実行

   クラスで共通の情報を使用        インスタンスの個別の情報を使用

 

 

クラスメソッドとインスタンスメソッドの違い

クラスメソッドは、インスタンスの親玉であるクラス自身が利用する技。
例えば、レビューの総数ならば、これは個々のレビューではなくレビュークラスが扱うべき情報。
またnewメソッドも実はクラスメソッド。newメソッドは「インスタンスを生成する」という振る舞いだが、こちらも個々のレビューではなくクラスが行うべきこと。

インスタンスメソッドは、各インスタンスが行う技。例えば「レビューの内容を表示する」メソッドは、各レビューのインスタンスの属性値を使用するので、インスタンスメソッドとして定義するのがふさわしい。

 

要点チェック

 

クラスメソッドの利用

- 定義

クラスメソッドの定義の仕方はいくつかあるが、すべてクラスの定義内で行う。クラスメソッドはメソッド名の前にself.を付ける。

1
2
3
4
5
  class クラス名
    def self.メソッド名
      # 処理
    end
  end

- 呼び出し

呼び出しは、クラス名に続けてメソッド名を書く。引数は()の中にいれる。ここは普通のメソッドと同様。

1
  クラス名.メソッド名(引数)

代表的なクラスメソッドはnewメソッド

1
  user = User.new

では、Reviewクラスにクラスメソッドを定義してみる。ここで定義するメソッドは書いたレビューの数を返すというメソッド。

書いたレビューの数は、Reviewクラスのインスタンスの数なので、クラスで共通の情報。なので、クラスメソッドを使用する。メソッド名はget_review_countにする。

 

1
2
3
4
5
6
7
8
class Review
  def self.get_review_count
    return 0
  end
end

review = Review.new # Reviewクラスのインスタンスを生成
puts review

数を返すのでreturn文を使ってレビュー数を返すようにする。この後に、実際に書いたレビューの数を返すようにするが、今のところは便宜的に0を返すようにする。

 

sample_class.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Review
  def self.get_review_count
    return 0
  end
end

review = Review.new # Reviewクラスのインスタンスを生成
puts review

puts Review.get_review_count

要点チェック

 

インスタンスメソッドの定義

- 定義

インスタンスメソッドの定義はそのインスタンスのクラスの定義内で行う。普通のメソッドと書き方は同じ。

1
2
3
4
5
  class クラス名
    def メソッド名
      # 処理
    end
  end

- 呼び出し

呼び出しは、インスタンスに続けてメソッド名を書く。引数は()の中にいれる。ここは普通のメソッドと同様。

1
  インスタンス.メソッド名(引数)

では、Reviewクラスにインスタンスメソッドを定義してみる。ここで定義するメソッドはレビューの内容を表示するというメソッド。先の項で説明した通り、レビューの内容は、Reviewクラスのインスタンスごとの個別の値(属性値)インスタンスが個別に持つ値を利用したいので、インスタンスメソッドとして定義する。
メソッド名はshow_reviewにする。

sample_class.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Review
  def self.get_review_count
    return 0
  end

  def show_review
    puts "ジャンル : " + "映画"
    puts "---------------------------"
    puts "タイトル : " + "るろうに剣心"
    puts "---------------------------"
    puts "感想 :"
    puts "アクションがすごい!"
    puts "---------------------------"
  end
end

review = Review.new # Reviewクラスのインスタンスを生成
puts review

puts Review.get_review_count

ここも最終的には実際に作成したレビューの内容(Reviewクラスのインスタンスの属性値)を表示するようにするが、まずは便宜的にテンプレートのレビューを返すようにする。 

では、いま定義したインスタンスメソッドを呼び出してみる。

sample_class.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
 class Review
  def self.get_review_count
    return 0
  end

  def show_review
    puts "ジャンル : " + "映画"
    puts "---------------------------"
    puts "タイトル : " + "るろうに剣心"
    puts "---------------------------"
    puts "感想 :"
    puts "アクションがすごい!"
    puts "---------------------------"
  end
end

review = Review.new # Reviewクラスのインスタンスを生成
review.show_review

puts Review.get_review_count

 

クラスメソッドとインスタンスメソッドの違い

クラスメソッドとインスタンスメソッドの違いを整理しておく。

 

クラスメソッドは、

クラスに対して使用し、クラスで共通の情報を使用する。つまり、インスタンスの個別の情報は関係ない


インスタンスメソッドは、

インスタンスに対して使用し、インスタンスごとに異なる個別の情報を使用する。

 

書き方の違いも確認しておく。

両方ともクラスの定義内に書く。しかし、

クラスメソッドはdef self.classMethodのようにself.をメソッド名の前につけ、

インスタンスメソッドdef instanceMethodのようにself.をつけない

特徴 インスタンスメソッド クラスメソッド
定義方法

メソッド名の前にselfは

つけない

メソッド名の前にselfを

つける

用途

インスタンスごとの属性を

用いる場合

属性は関係のない共通の処理
呼び出せるオブジェクト クラスのインスタンス クラス自身

 

 

 

クラス変数とインスタンス変数を理解しよう

共通の属性の定義の方法。

クラスでは、共通の属性は変数として定義する。そして、その変数に代入した値が属性値という。
そして、その変数は、クラス変数インスタンス変数にわかれる。

クラスに定義できる変数にはクラス変数インスタンス変数の2種類ある。

 クラス変数

クラス全体で使用できる変数。クラス内であればどこでも使えるのでクラスメソッド、インスタンスメソッドの両方で使うことが出来る。クラスを通して、値が共通の情報に使用する。

 インスタンス変数

共通の属性としてインスタンスに定義できる変数。その値は、個々のインスタンスによって別々に設定できる。

レビュー管理アプリケーションで使用される情報を、クラス変数・インスタンス変数に分けると以下のようになる。

 

 

    レビュークラス            レビュークラスのインスタンス

  クラス変数              インスタンス変数

    作成されたレビューの総数       タイトル/ジャンル/感想

      ↓                       ↓

   クラス内のどこでも使用可能       各インスタンス内でのみ使用可能

    クラスで共通の情報            インスタンスの個別の情報

 

 

まず、作成されたレビューの総数は、クラス内で変わらない共通の情報。なので、クラス内のどこでも参照されるべき。なので、クラス変数を使用する。
一方で、タイトル感想は、各レビューごとに異なる。抽象的に言えば、インスタンスごとに値のことなる情報。そのため、インスタンス変数を使用する。

 

インスタンス変数の定義

インスタンス変数の定義はインスタンスメソッドの定義内で行う。インスタンス変数は変数名の始めに@(アットマークを1つ)をつけて宣言する。

sample
1
2
3
4
5
  class クラス名
    def sample
      @test = "ex"
    end
  end

あるインスタンスメソッドの中でインスタンス変数を定義すると、そのメソッドを利用したインスタンスの固有の値として定義される。
Reviewクラスのインスタンスの属性として、インスタンス変数を定義してみる。ここで定義する変数はタイトル、ジャンル、感想なので、変数名は@title@genre@impressionとする。

 sample_class.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
class Review
  def self.get_review_count
    return 0
  end

  def write_review
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
  end

  def show_review
    puts "ジャンル : " + "映画"
    puts "---------------------------"
    puts "タイトル : " + "るろうに剣心"
    puts "---------------------------"
    puts "感想 :"
    puts "アクションがすごい!"
    puts "---------------------------"
  end
end


review = Review.new
review.write_review
review.show_review

puts Review.get_review_count

write_reviewメソッド内で、自分が入力した値が、インスタンス変数@title@genre@impressionに代入されるようにした。

上記のコードの処理の流れを追ってみると、

27行目でReviewクラスのインスタンスを生成。

次に、28行目のreview.write_reviewという記述により、

27行目で生成したreviewクラスのインスタンスwrite_reviewというインスタンスメソッドを使用している。

そのwrite_reviewメソッド内で、インスタンス変数@title@genre@impressionの定義をする。つまり、インスタンスが生成された直後に、インスタンスの属性値(インスタンス変数)を設定するようにした。

  

では、いま定義したインスタンス変数@title@genre@impressionを活用してみる。あるインスタンスインスタンス変数の値は、そのインスタンスが利用したメソッドの中で、以下のように利用できる。

 sample_class.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
class Review
  def self.get_review_count
    return 0
  end

  def write_review
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
  end

  def show_review
    line = "---------------------------"
    puts "ジャンル : #{@genre}\n#{line}\n"
    puts "タイトル : #{@title}\n#{line}\n"
    puts "感想 :\n#{@impression}\n#{line}\n"
  end
end


review = Review.new
review.write_review
review.show_review

puts Review.get_review_count

これで、write_reviewメソッドで定義したインスタンスの属性値(インスタンス変数)をshow_reiviewメソッドで参照できるようにした。

ここで大切なのはインスタンスメソッドの中でのインスタンス変数(@が付いた変数)の値は、そのインスタンスメソッドを利用したインスタンスが持つインスタンス変数の値になるということ。

  

実際にsample_class.rbを実行して、処理の流れを理解する

手順を順に追っていくと、
1. 24行目で、Reviewクラスのインスタンスを生成する。
2. 25行目で、24行目で作成したインスタンスがwrite_reviewメソッドを使用し、インスタンス変数に値を入れることで、インスタンスの属性値を定義する。
3. 26行目で、24行目で作成したインスタンスに対してshow_reviewメソッドを使用し、write_reviewメソッドで定義したインスタンスの属性値を参照する。

 

要点チェック

 

クラス変数の定義

次に、クラス変数を定義する。クラス変数は、クラスの範囲内であればどこからでも参照できる変数。
クラス変数の定義はクラスの定義内で行う。クラス変数は変数名の始めに@@(アットマーク2つ)をつけて宣言する。

1
2
3
  class クラス名
    @@クラス変数
  end

では、Reviewクラスにクラス変数を定義する。ここで定義する変数は書いたレビューの数が代入されることとし、変数名は@@review_countにする。

sample_class.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
class Review
  @@review_count = 0
  def self.get_review_count
    return @@review_count
  end

 def write_review
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
  end

  def show_review
    line = "---------------------------"
    puts "ジャンル : #{@genre}\n#{line}\n"
    puts "タイトル : #{@title}\n#{line}\n"
    puts "感想 :\n#{@impression}\n#{line}\n"
  end
end

review = Review.new
review.write_review
review.show_review

puts Review.get_review_count

クラスの定義の一番最初に@@review_countを定義する。レビュー数は最初0なので0を代入する。
これで、クラスを通して共通の情報であるレビュー数を、0として定義している。そして、28行目でget_review_countクラスメソッドを使い、@@review_countに定義した値を参照している。

しかし、このままでは、レビューが作成されても、レビューの数は0のままになってしまう。そこで、レビューが作成されるごとに、@@review_countの値が更新されるようにする。

 

sample_class.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
class Review
  @@review_count = 0
  def self.get_review_count
    return @@review_count
  end

 def write_review
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
    @@review_count = @@review_count + 1
  end

  def show_review
    line = "---------------------------"
    puts "ジャンル : #{@genre}\n#{line}\n"
    puts "タイトル : #{@title}\n#{line}\n"
    puts "感想 :\n#{@impression}\n#{line}\n"
  end
end

review = Review.new
review.write_review
review.show_review

puts Review.get_review_count

write_reivewメソッド内に、@@review_countの値を1増やして更新するようにした。こうすることで、レビューが作成されるごとに、レビューの数を記録するクラス変数@@review_countの値が1ずつ増えていくようになった。

 2行目で@@review_count = 0と書いてあるが、ここが呼ばれるのはクラスを定義した最初の一回だけ。この@@review_count = 0によって毎回@@review_countの値が0になってしまうことはない。

実際に、sample_class.rbを実行してみる。レビューを作成すると、「1」と出力されたら成功。

 

要点チェック

 

クラス変数とインスタンス変数の違いを理解する

改めて、クラス変数とインスタンス変数の使い方・違いについて理解しておく。

クラス変数は、クラスで共通の情報に対して使用する。つまり、クラスを通して、1つの値となる。
インスタンス変数は、インスタンスごとに異なる個別の情報(属性値)に対して使用する。つまり、インスタンスごとに値は異なる

人クラスでイメージすると以下のようになる。

https://tech-master.s3.amazonaws.com/uploads/curriculums//0d24aa193b237783809bf96357e3f622.png

このように、クラス内で変わらない共通の情報には、@@を二つ付けるクラス変数を使用する。
そして、インスタンスごとに異なる個別の情報には、@が一つのインスタンス変数を使用する。

さらに、インスタンス変数について見ると以下のようになる。

https://tech-master.s3.amazonaws.com/uploads/curriculums//1d302e227ac18f8466866e21ed555cc5.png

このように、インスタンス変数は、同じ変数名でもインスタンスごとに値が異なる。つまり、インスタンスが複数生成されている場合、インスタンスごとにインスタンス変数の値を定義するということになる。

また、クラス変数とインスタンス変数の間には使用できる場所にも違いがある。
まず、クラス変数はあくまでクラス内のどこでも使用可能なので、クラスメソッドでも、インスタンスメソッドでも、メソッドの外でも使用可能。

 

          @@review_count(クラス変数)

        使える  ↑                                         ↑  使える

     レビュークラス(Review)     レビュークラスのインスタンス

                  

しかし、インスタンス変数はインスタンスでしか使えず、その値もインスタンスごとに違う。使えるメソッドも、インスタンスメソッドのみになる。

          @title(インスタンス変数)

                                  ↑     

                                  使える 

                                    ↑            

                      @title= "るろうに剣心"        @title="君に届け"                        

             レビュークラスのインスタンス

                  @titleはインスタンスごとに異なる

                     

では最後にインスタンスごとにインスタンス変数の値が異なることを確認する。sample_class.rbを書き換えてみる。

  • メニュー画面を作成して何回もレビューを書けるようにする
  • メニュー画面で今まで書いたレビューの数を表示する

 

sample_class.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
class Review
  @@review_count = 0
  def self.get_review_count
    return @@review_count
  end

  def write_review
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
    @@review_count = @@review_count + 1
  end

  def show_review
    line = "---------------------------"
    puts "ジャンル : #{@genre}\n#{line}\n"
    puts "タイトル : #{@title}\n#{line}\n"
    puts "感想 :\n#{@impression}\n#{line}\n"
  end
end

while true do
  # メニューの表示
  puts "書いたレビューの数:#{Review.get_review_count}"
  puts "[0]レビューを書く"
  puts "[1]アプリを終了"
  input = gets.to_i

  if input == 0    # レビューを書く
    review = Review.new
    review.write_review
    review.show_review
  elsif input == 1 # アプリを終了
    exit
  else             # その他の入力
    puts "入力された値は無効な値です"
  end
end

これでレビューを自分で書けるようになり、Reviewクラスのインスタンスを複数つくれるようになった。33行目から35行目をみると、

sample_class.rb
33
34
35
  review = Review.new
  review.write_review
  review.show_review

[0]レビューを書くを選択したときにこの部分の処理が実行される。レビューを書くごとに新しくReviewクラスのインスタンスを生成していることがわかる。インスタンス変数はインスタンスごとに異なり(ジャンル、タイトル、感想)、クラス変数はクラス全体で1つだけ(レビュー数)となっている。例えばレビューを3回書くとすると、以下の図のようになる。

インスタンス変数

クラス変数とインスタンス変数の違い

  クラス変数 インスタンス変数
変数名 最初に@@(アットマーク2つ) 最初に@(アットマーク1つ)
使えるメソッド クラスメソッドとインスタンスメソッド インスタンスメソッド
クラスとインスタンスで共通 インスタンスごとに異なる

initializeメソッド

initializeメソッドを定義することで、インスタンスの生成と同時に実行したい処理を自動的に実行することができる
インスタンスの生成と同時に実行したい処理というのは、例えば、インスタンスの属性値の設定などである。
今回作っているレビュー管理アプリケーションでは、newメソッドでインスタンスを作成した直後に、インスタンスにwrite_reviewメソッドを実行させることで、インスタンスの属性値を設定していた。属性値の設定の処理をインスタンスの生成の次の行に書くことでインスタンスが生成されたら必ず属性値が設定されるようにしていたが、本来属性値の設定は、インスタンスの生成とセットで実行されるべきである。なぜならば、何らかのレビューなのに各属性値を持っていないわけがないから。
そこで、initializeメソッドを使用する。

 initializeメソッド

initializeメソッドは、インスタンスが生成された瞬間に、今まさに生成されたそのインスタンスに必ず利用されるインスタンスメソッド。

initializeメソッドの具体的内容は自分で書く必要がある。インスタンス生成のときに何か処理を行いたいときはinitializeメソッドを書くようにする。

以下の例において、8行目のクラス名.newという記述によって、クラス名のインスタンスが生成される。このインスタンスが生成されたタイミングで、initializeメソッドが自動的に実行される。今、initializeメソッドでは”クラス名のインスタンスが生成されました”を出力するという記述がされているので、ターミナルで実行するとそのように表示される。

1
2
3
4
5
6
7
8
9
  class クラス名
    def initialize
      # 生成のときの処理
      puts "クラス名のインスタンスが生成されました" # 例
    end
  end

  インスタンス = クラス名.new # initializeメソッドが呼ばれ
                               "クラス名のインスタンスが生成されました"と表示される

 

要点チェック

 

sample_class.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
class Review
  @@review_count = 0
  def self.get_review_count
    return @@review_count
  end

  def initialize
    puts "Reviewクラスのインスタンスが生成されました"
  end

  def write_review
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
    @@review_count = @@review_count + 1
  end

  def show_review
    line = "---------------------------"
    puts "ジャンル : #{@genre}\n#{line}\n"
    puts "タイトル : #{@title}\n#{line}\n"
    puts "感想 :\n#{@impression}\n#{line}\n"
  end
end

while true do
  # メニューの表示
  puts "書いたレビューの数:#{Review.get_review_count}"
  puts "[0]レビューを書く"
  puts "[1]アプリを終了"
  input = gets.to_i

  if input == 0    # レビューを書く
    review = Review.new
    review.write_review
    review.show_review
  elsif input == 1 # アプリを終了
    exit
  else             # その他の入力
    puts "入力された値は無効な値です"
  end
end

38行目でレビューを書かせるwrite_reviewメソッドを呼ぶ前に37行目でreview = Review.newでinitializeメソッドが呼ばれる。
レビューを書かせる指示が表示される前に、"Reviewクラスのインスタンスが生成されました"と表示されたら成功。

 

次に、initializeメソッド内の記述を編集して、インスタンスの生成と同時に、レビューが作成され、さらにレビューの総数のカウントも増やすようにする。

 下記のようにコードを編集して、initializeメソッド内に、write_reviewメソッド内の記述を移動させ、write_reviewメソッドの記述を削除する。

sample_class.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
class Review
  @@review_count = 0
  def self.get_review_count
    return @@review_count
  end

  def initialize
    puts "タイトルを入力してください"
    @title = gets.chomp
    puts "ジャンルを入力してください"
    @genre = gets.chomp
    puts "感想を入力してください"
    @impression = gets.chomp
    @@review_count = @@review_count + 1
  end

  def show_review
    line = "---------------------------"
    puts "ジャンル : #{@genre}\n#{line}\n"
    puts "タイトル : #{@title}\n#{line}\n"
    puts "感想 :\n#{@impression}\n#{line}\n"
  end
end

while true do
  # メニューの表示
  puts "書いたレビューの数:#{Review.get_review_count}"
  puts "[0]レビューを書く"
  puts "[1]アプリを終了"
  input = gets.to_i

  if input == 0    # レビューを書く
    review = Review.new
    review.show_review
  elsif input == 1 # アプリを終了
    exit
  else             # その他の入力
    puts "入力された値は無効な値です"
  end
end

まず、7-15行目のように、initializeメソッドにwrite_reviewメソッドの中身をそのまま移した。つまり、33行目のReview.newインスタンスが生成されると同時にinitializeメソッドが実行され、8-15行目でレビューが生成(インスタンスの属性値として設定)される。さらに、14行目でクラス変数@@review_countの値を1増やして更新することで、レビューの総数の情報を更新した。つまり、インスタンスの生成の後にwrite_reviewメソッドで行っていた処理を、インスタンスの生成と同時に自動で実行されるようにした。
そうすると、今までのwrite_reviewメソッドは不要になる。そこで、16行目のようにinitializeメソッドとshow_reviewメソッドの間に書いてあったwrite_reviewメソッドの定義の記述を削除し、33-34行目のあたりにあったwrite_reviewメソッドを呼び出す記述も削除した。

以上のように、initializeメソッドを使用することで、インスタンスが生成されると同時に必ず実行したい処理を自動で実行することができる。
そして、主に、インスタンスの属性値の設定(インスタンス変数の定義)のような、インスタンスが必ず持っていなければいけない値の設定などに使用する。

 

クラスの継承

複数のクラスに同じメソッドを定義したい場合、それぞれのクラスに全てのメソッドを定義すると、同じ記述を何度も繰り返す事になってしまう。結果コード量が多くなり、管理も難しくなる。これを防ぐために「クラスの継承」を行う。

 クラスの継承

あるクラスに定義されたメソッドを、別のクラスで利用出来るようにすることを継承と言う。

クラスの継承には、親クラスと子クラスの関係がある。元となるクラスを親クラス、親クラスのメソッドを引き継ぎ新しく作成するクラスを子クラス と呼ぶ。


では具体的な例を見てみる。

ここでは、2つのクラスを作成したいとする。パトカーのようなインスタンスを生成するクラスとトラックのようなインスタンスを生成するクラス。どちらも共通して車としての特徴を持っているので、共通する「車としての特徴」を親クラスCarの中でまとめ、パトカーとトラックそれぞれの特徴はそれぞれのクラスPatrolCar, TruckCarでのみ定義することとする。

車の特徴(親クラス)

  • 加速する
  • 減速する
  • ホーンを鳴らす

パトカーだけの特徴(子クラス)

  • サイレンを鳴らす

トラックだけの特徴(子クラス)

  • 荷物を運ぶ

車の特徴(親クラス)を継承する事で、パトカー(子クラス)とトラック(子クラス)に車の特徴を記述する必要がなくなる。結果、パトカーとトラックだけの特徴が分かりやすくなっている。


では実際にコードで書くと、

継承をする際には、クラスを宣言する際に「<」を用いて、以下のように記述する。

1
class 子クラス名 < 親クラス名

Carクラス (親クラス)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  class Car
    def speed_up
      puts "加速します"
    end

    def speed_down
      puts "減速します"
    end

    def horn
      puts "プップー"
    end
  end

PatrolCarクラス (子クラス)

1
2
3
4
5
  class PatrolCar < Car #クラスの継承
    def siren
      puts "ピーポーピーポー"
    end
  end

TruckCarクラス (子クラス)

1
2
3
4
5
  class TruckCar < Car #クラスの継承
    def carry
      puts "荷物を運びます"
    end
  end

親クラスと子クラスで使えるメソッドをそれぞれ比較。

メソッド名 Car(親クラス) PatrolCar(子クラス)
speed_up
speed_down
horn
siren ×

 

メソッド名 Car(親クラス) TruckCar(子クラス)
speed_up
speed_down
horn
carry ×

 

親クラスに共通のメソッドを定義することで、子クラスのコード量が少なくなり見やすくなっている。また親クラスで定義された共通のメソッドを変更するだけで、変更を子クラスへ容易に反映できることがわかる。

複数のクラスで共通のメソッドを用いる時は、親クラスを作成して共通のメソッドを定義し、子クラスへ継承する。