Ruby | 2週間で身につく、アプリを作りながら学ぶRubyの基本 - 5日目

Ruby Ruby
スポンサーリンク

5日目のゴールとテーマ

5日目のテーマは「ハッシュから一歩進んで、“自分の型(クラス)”を作る」です。
4日目までは、1人分の情報をハッシュで表現していました。

今日はそこから一歩進めて、

「人」を表す Person クラスを作る
person.nameperson.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.name
person[: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 クラスは「人」を表す設計図。

initialize
Person.new(...) したときに自動で呼ばれる特別なメソッド。
引数を受け取り、インスタンス変数(@name など)にセットする。

インスタンス変数(@name など)
そのオブジェクト専用の“中身”。
クラスの中のどのメソッドからもアクセスできる。

attr_accessor
person.nameperson.name = "..." のように、
外から読み書きできる属性を定義するためのショートカット。

メソッドをクラスに持たせる
age_comment や introduction のように、
そのクラスに関係する処理をクラスの中に閉じ込めることで、
「そのクラスを見れば、その概念に関することが分かる」状態になる。

タイトルとURLをコピーしました