クラスとインスタンスのコード理解
Rubyのオブジェクトは、全ていずれかのクラスのインスタンスである。
例えば、今まで使っていた"Hello World"のような文字列はStringクラスのインスタンス。
1 2 |
string1 = "Hello World" # インスタンス
string2 = "こんにちは Ruby" # インスタンス
|
この"Hello World"と"こんにちは"は、それぞれ文字列のオブジェクト。もちろん中身の文字は違うが、文字を持つということは共通している。
さらに、文字列のオブジェクトであれば、以下のように共通のメソッドが使用できる。
1 2 3 4 5 6 |
string1 = "Hello World"
string2 = "こんにちは"
# どちらもlengthメソッドが使える
puts string1.length
puts string2.length
|
これまで文字列は使用していても、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クラスの定義
1 2 3 |
class Review
end
|
インスタンスを生成
定義したクラスからインスタンスを生成する。
インスタンスは、クラスのnewメソッド(定義しなくても利用できる)を実行させることにより生成される。
レビュークラス(Review) →(newメソッド)→ レビュークラスのインスタンス
newメソッド
全てのクラスは、定義しなくてもnew
という特別なメソッドを持っている。
このメソッドは、返り値として利用したクラスのインスタンスを返す。
Reviewクラスのインスタンス、reviewを生成
1 2 3 4 5 |
class Review
end
review = Review.new # Reviewクラスのインスタンスを生成
puts review
|
このように、クラスの定義と通常のRubyの記述は同じファイル内に書くことができる。
続いて、ターミナルからsample_class.rb
を実行。
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を返すようにする。
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
にする。
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クラスのインスタンスの属性値)を表示するようにするが、まずは便宜的にテンプレートのレビューを返すようにする。
では、いま定義したインスタンスメソッドを呼び出してみる。
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つ)をつけて宣言する。
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
にする。
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の値が更新されるようにする。
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つの値となる。
インスタンス変数は、インスタンスごとに異なる個別の情報(属性値)に対して使用する。つまり、インスタンスごとに値は異なる。
人クラスでイメージすると以下のようになる。
このように、クラス内で変わらない共通の情報には、@@を二つ付けるクラス変数を使用する。
そして、インスタンスごとに異なる個別の情報には、@が一つのインスタンス変数を使用する。
さらに、インスタンス変数について見ると以下のようになる。
このように、インスタンス変数は、同じ変数名でもインスタンスごとに値が異なる。つまり、インスタンスが複数生成されている場合、各インスタンスごとにインスタンス変数の値を定義するということになる。
また、クラス変数とインスタンス変数の間には使用できる場所にも違いがある。
まず、クラス変数はあくまでクラス内のどこでも使用可能なので、クラスメソッドでも、インスタンスメソッドでも、メソッドの外でも使用可能。
@@review_count(クラス変数)
使える ↑ ↑ 使える
レビュークラス(Review) レビュークラスのインスタンス
しかし、インスタンス変数はインスタンスでしか使えず、その値もインスタンスごとに違う。使えるメソッドも、インスタンスメソッドのみになる。
@title(インスタンス変数)
↑
使える
↑
@title= "るろうに剣心" @title="君に届け"
レビュークラスのインスタンス
@titleはインスタンスごとに異なる
では最後にインスタンスごとにインスタンス変数の値が異なることを確認する。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行目をみると、
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 |
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メソッドの記述を削除する。
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 | × | ◯ |
親クラスに共通のメソッドを定義することで、子クラスのコード量が少なくなり見やすくなっている。また親クラスで定義された共通のメソッドを変更するだけで、変更を子クラスへ容易に反映できることがわかる。
複数のクラスで共通のメソッドを用いる時は、親クラスを作成して共通のメソッドを定義し、子クラスへ継承する。