5日目のゴールとテーマ
5日目のテーマは「ハッシュから一歩進んで、“自分の型(クラス)”を作る」です。
4日目までは、1人分の情報をハッシュで表現していました。
今日はそこから一歩進めて、
「人」を表す Person クラスを作るperson.name や person.age のように扱えるようにする
自己紹介文を作るメソッドを Person の中に持たせる
という、「オブジェクト指向」の入り口に入っていきます。
クラスとオブジェクトをイメージでつかむ
設計図(クラス)と実物(オブジェクト)
クラスは「設計図」、オブジェクトは「その設計図から作られた実物」と考えると分かりやすいです。
Person というクラスは、「人ってこういう情報を持っているよね」という設計図です。
例えば、名前・年齢・趣味・年齢コメントなど。
そこから実際に作られた1人分のデータが、Person オブジェクトです。
「たろうさん」という人を表す Person
「はなこさん」という人を表す Person
という感じで、同じ設計図から何人分でも作れます。
Personクラスを定義してみる
最小限のPersonクラス
まずは、名前・年齢・趣味だけを持つシンプルな Person クラスを書いてみます。
class Person
attr_accessor :name, :age, :hobby
def initialize(name, age, hobby)
@name = name
@age = age
@hobby = hobby
end
end
Rubyここで出てきた新しい要素を、丁寧に分解します。
attr_accessorとは何か
attr_accessor :name, :age, :hobby は、
name, age, hobby という「属性(プロパティ)」を
外から読み書きできるようにするための“おまじない”
です。
これを書いておくと、
person = Person.new("たろう", 25, "ゲーム")
puts person.name # 読める
person.hobby = "読書" # 書ける
Rubyのように、ドットでアクセスできます。
initializeと@変数
def initialize(name, age, hobby) は「コンストラクタ」と呼ばれる特別なメソッドです。Person.new(...) したときに、自動的に呼ばれます。
@name や @age のような @ から始まる変数は「インスタンス変数」と呼ばれます。
そのオブジェクト専用の“中身”を表します。
@name = name は、
引数で受け取った name を、この人(オブジェクト)の @name に保存する
という意味です。
Personオブジェクトを作って使ってみる
newで「1人分の人」を作る
さっそく Person を使ってみます。
person1 = Person.new("たろう", 25, "ゲーム")
person2 = Person.new("はなこ", 19, "カフェ巡り")
puts person1.name
puts person1.age
puts person1.hobby
puts person2.name
puts person2.age
puts person2.hobby
Ruby実行すると、それぞれの人の情報が表示されます。
ここで感じてほしいのは、
「ハッシュのキーでアクセスしていたものが、ドットでアクセスできるようになった」
ということです。
person[:name] ではなく person.nameperson[:age] ではなく person.age
のように書けると、「人」という概念がコードの中でより自然に扱えます。
Personに「年齢コメントを返すメソッド」を持たせる
ロジックをクラスの中に閉じ込める
4日目では、年齢コメントを決めるメソッドを別に書いていました。
これを Person の中に入れてしまいましょう。
class Person
attr_accessor :name, :age, :hobby
def initialize(name, age, hobby)
@name = name
@age = age
@hobby = hobby
end
def age_comment
if @age <= 0
"年齢はひみつなんですね。"
elsif @age < 20
"とても若いですね!"
elsif @age < 40
"働き盛りの世代ですね。"
else
"人生経験が豊富そうですね。"
end
end
end
Rubyここでの重要ポイントは、
年齢コメントのロジックが Person の中に移動した@age を直接使って判定している
外からは person.age_comment と呼ぶだけでよくなる
ということです。
実際に呼んでみる
person = Person.new("たろう", 25, "ゲーム")
puts person.name
puts person.age
puts person.hobby
puts person.age_comment
Rubyこれで、「この人に対するコメント」を
Person 自身が知っている、という形になります。
Personに「自己紹介文を返すメソッド」を持たせる
自己紹介の責任もPersonに渡す
今度は、自己紹介文を作るメソッドも Person に持たせます。
class Person
attr_accessor :name, :age, :hobby
def initialize(name, age, hobby)
@name = name
@age = age
@hobby = hobby
end
def age_comment
if @age <= 0
"年齢はひみつなんですね。"
elsif @age < 20
"とても若いですね!"
elsif @age < 40
"働き盛りの世代ですね。"
else
"人生経験が豊富そうですね。"
end
end
def introduction
text = ""
text += "はじめまして、#{@name}です。\n"
text += "年齢は#{@age}歳です。#{age_comment}\n"
text += "好きなことは#{@hobby}です。\n"
text += "よろしくお願いします!\n"
text
end
end
Rubyここで深掘りしたいポイントは、
自己紹介文の中で age_comment メソッドを呼んでいる@name, @age, @hobby を直接使って文章を組み立てている
最後に text を返している(Rubyでは最後の式が戻り値になる)
ということです。
これで、外からはこう書けます。
person = Person.new("たろう", 25, "ゲーム")
puts person.introduction
Ruby「自己紹介を作る」という責任が、Person クラスの中にきれいに収まりました。
入力からPersonオブジェクトを作る
ユーザー入力を使ってPersonを生成する
今度は、gets を使って Person を作るメソッドを書きます。
def build_person_from_input
puts "あなたの名前を教えてください:"
name = gets.chomp
puts "あなたの年齢を教えてください:"
age_text = gets.chomp
age = age_text.to_i
puts "あなたの好きなこと(趣味)を教えてください:"
hobby = gets.chomp
person = Person.new(name, age, hobby)
person
end
Rubyここでの流れは、
名前・年齢・趣味を聞く
年齢は to_i で整数に変換する
Person.new で1人分のオブジェクトを作る
その Person を戻り値として返す
というものです。
これで、入力から直接 Person を作れるようになりました。
Personの配列で「名簿アプリ」にする
複数人分のPersonを配列にためる
4日目では「ハッシュの配列」でしたが、
5日目では「Person の配列」にしてみます。
puts "何人分の情報を登録しますか?"
count_text = gets.chomp
count = count_text.to_i
people = []
i = 1
while i <= count
puts "========================"
puts "#{i}人目の情報を入力します。"
person = build_person_from_input
people << person
i += 1
end
Rubyこれで、people には Person オブジェクトが順番に入ります。
全員分の自己紹介を表示する
puts "========================"
puts "全員分の自己紹介を表示します。"
people.each_with_index do |person, idx|
puts "------------------------"
puts "#{idx + 1}人目の自己紹介:"
puts person.introduction
end
Rubyここでのポイントは、
配列の中身が「ただの文字列」でも「ハッシュ」でもなく、「Person オブジェクト」になっている
自己紹介文は person.introduction と呼ぶだけでよい
年齢コメントのロジックも Person の中に隠れている
ということです。
クラスを使うメリットを整理する
「データ」と「振る舞い」がひとまとまりになる
ハッシュのときは、
データ(name, age, hobby)はハッシュ
年齢コメントのロジックは別メソッド
自己紹介文を作るロジックも別メソッド
という形でした。
クラスにすると、
Person が「データ(@name, @age, @hobby)」と
「振る舞い(age_comment, introduction)」を両方持つ
という形になります。
「人に関することは Person を見れば分かる」という状態です。
コードの読みやすさが上がる
例えば、こんなコードを見たときに、
people.each do |person|
puts person.introduction
end
Ruby「people に入っている“人たち”が、順番に自己紹介しているんだな」
と、ほぼ日本語の感覚で読めます。
クラスをうまく設計すると、
コードが「何をしたいのか」をそのまま表現してくれるようになります。
5日目のまとめ
今日のキーワードを整理します。
class
自分で新しい「型(設計図)」を定義するためのキーワード。
Person クラスは「人」を表す設計図。
initializePerson.new(...) したときに自動で呼ばれる特別なメソッド。
引数を受け取り、インスタンス変数(@name など)にセットする。
インスタンス変数(@name など)
そのオブジェクト専用の“中身”。
クラスの中のどのメソッドからもアクセスできる。
attr_accessorperson.name や person.name = "..." のように、
外から読み書きできる属性を定義するためのショートカット。
メソッドをクラスに持たせる
age_comment や introduction のように、
そのクラスに関係する処理をクラスの中に閉じ込めることで、
「そのクラスを見れば、その概念に関することが分かる」状態になる。
