【Ruby】レッスン5-03:アクセスメソッドを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:アクセスメソッド

この記事の練習問題を解くために必要な知識:
基礎文法、制御構造、メソッド、コレクション(レッスン1~4)クラスの定義と使用イニシャライザアクセスメソッドクラス変数とクラスメソッドprivateメソッド正規表現クラスの継承ファイル操作オーバーライドモジュールの定義と使用ミックスイン

<<前のページ Ruby記事一覧 次のページ>>

Rubyの「アクセスメソッド」とは

ここではアクセスメソッドの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。

Rubyでプログラムを作成する際、クラスの内部に定義される「インスタンス変数」というものがあります。

この変数はクラス内で使用されるデータを保持しますが、外部から直接アクセスすることはできません。

そのため外部からインスタンス変数を安全に操作する方法として「アクセスメソッド」を使います。アクセスメソッドには次の2つがあります。

  1. ゲッター: 変数の値を取得するメソッド
  2. セッター: 変数の値を変更するメソッド

Rubyではこれらのメソッドを自動的に作成する便利な機能attr_accessorも用意されています。

本記事ではこのアクセスメソッドについて具体例を交えながら分かりやすく解説していきます。

なぜアクセスメソッドが必要なのか?

まずアクセスメソッドがなぜ重要なのかを説明します。

Rubyではインスタンス変数を定義する際に@をつけます。この変数はクラス内からは参照できますが、外部から直接参照することはできません。

直接アクセスできない例

class User
  def initialize(name)
    @name = name # インスタンス変数の定義
  end
end

user = User.new("Taro")
# クラスの外からインスタンス変数にアクセス
puts user.name # エラー: undefined method `name' for #<User:...>

このエラーはインスタンス変数@nameがクラス外から直接参照できないために発生しています。

外部から安全に変数へアクセスする方法として、ゲッターやセッターを使います。

ゲッターとセッターの仕組み

ゲッターとセッターを手動で定義することで、インスタンス変数の値を取得したり設定したりすることができます。

ゲッターの定義

ゲッターはインスタンス変数の値を取得するためのメソッドです。

class User
  def initialize(name) # initializeメソッドは、新しいインスタンスが作成されるときに呼び出される
    @name = name       # 引数nameを受け取り、インスタンス変数@nameに代入する
  end

  # クラスの中にゲッターを定義
  def name # このnameメソッドを呼び出すことで、インスタンス変数@nameの値を取得できる
    @name  # nameメソッド(ゲッターメソッド)の戻り値
  end
end

# Userクラスの新しいインスタンスを作成
user = User.new("Taro") # "Taro"をインスタンス変数@nameに保存
puts user.name          # => "Taro"(ゲッターで値を取得)

セッターの定義

セッターはインスタンス変数の値を変更するためのメソッドです。

=を使うことで、見た目が変数への代入のようになります。

class User
  def initialize(name)
    @name = name
  end

  # クラスの中にセッターを定義
  def name=(value) # name=メソッドを呼び出すことで、インスタンス変数@nameの値を変更できる
    @name = value  # インスタンス変数@nameに新しい値を代入
  end
end

# Userクラスの新しいインスタンスを作成
user = User.new("Taro")
user.name = "Hanako" # インスタンス変数@nameに新しい値"Hanako"を設定

attr_accessorの活用

Rubyではゲッターとセッターを一つずつ手動で書く必要はありません。

attr_accessorを使えばゲッターとセッターを一括で作成できます。

attr_accessorを使った例

class User
  # ゲッターとセッターを自動生成
  attr_accessor :name # nameメソッド(ゲッター)とname=メソッド(セッター)が自動的に定義される

  def initialize(name)
    @name = name
  end
end

user = User.new("Taro")
puts user.name       # 自動生成されたゲッターメソッドを使用して@nameの値を取得 => "Taro"
user.name = "Hanako" # 自動生成されたセッターメソッドを使用して@nameの値を変更
puts user.name       # => "Hanako"

attr_accessor :nameの一行でゲッターとセッターの機能が追加されます。

これによりコードが簡潔になり、可読性が向上します。

attr_writerとattr_readerの説明

場合によってはゲッターだけ、またはセッターだけを定義したいことがあります。

そのような場合はattr_reader(ゲッターのみ)やattr_writer(セッターのみ)を使用します。

attr_readerの例

ゲッターのみを定義する場合の例です。

class User
  attr_reader :name # ゲッターのみ定義

  def initialize(name)
    @name = name
  end
end

user = User.new("Taro")
puts user.name  # => "Taro"
# user.name = "Hanako" # エラー(セッターが定義されていないため)

attr_writerの例

セッターのみを定義する場合の例です。

class User
  attr_writer :name # セッターのみ定義

  def initialize(name)
    @name = name
  end
end

user = User.new("Taro")
user.name = "Hanako"
# puts user.name # エラー(ゲッターが定義されていないため)

アクセスメソッドを使った実践例

アクセスメソッドを使うことでデータに対する制約を追加することもできます。

以下の例では、年齢が0以上の場合のみ値を変更するセッターを作成しています。

class User
  attr_reader :name
  attr_accessor :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  # 年齢を制限するセッター
  def age=(value)
    if value >= 0
      @age = value
    else
      puts "無効な年齢です"
    end
  end
end

user = User.new("Taro", 20)
puts user.name  # => "Taro"
puts user.age   # => 20
user.age = -5   # => "無効な年齢です"
puts user.age   # => 20(変更されない)

このようにセッターをカスタマイズすることで、不正なデータの入力を防ぐことができます。

まとめ

アクセスメソッドはオブジェクト指向プログラミングにおいて重要な役割を果たします。

ゲッターとセッターを使用することで、データの安全性を保ちながら操作が可能になります。

attr_accessorをはじめとするRubyの便利な機能を活用することで、簡潔で効率的なコードを書くことができます。

ぜひ自分のコードでも積極的に使ってみてください!

アクセスメソッドの練習問題:attr_accessorを学ぼう!

attr_accessorを使ったゲッターとセッターの自動生成について学びましょう。

名前と年齢を管理するPersonクラスを作成し、以下のような機能を持つプログラムを完成させてください。

プログラムの最後にはクラスのメソッドを使って、特定の動作を実行してみましょう。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. Personクラスを定義すること。
  2. attr_accessorを使用してnameageという2つのインスタンス変数のゲッターとセッターを自動生成すること。
  3. イニシャライザ(initializeメソッド)を作成し、nameageを初期化できるようにすること。
  4. have_birthdayというメソッドを作成し、年齢を1歳増やし、「〇〇さん、お誕生日おめでとうございます!」というメッセージを出力すること。
  5. Personクラスのインスタンスを生成し、以下の操作を行うこと:
    • 名前と年齢を取得し、画面に出力する。
    • 名前を変更し、変更後の名前を画面に出力する。
    • have_birthdayメソッドを呼び出し、結果を画面に出力する。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

名前: たかし
年齢: 20歳
新しい名前: ゆかり
ゆかりさん、お誕生日おめでとうございます!年齢は21歳になりました。

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:クラスPersonを定義
  □ attr_accessorを使用して、nameとageのゲッターとセッターを自動生成
  □ initializeメソッドを定義
  □ □ 引数nameをインスタンス変数@nameに代入
  □ □ 引数ageをインスタンス変数@ageに代入
  □ have_birthdayメソッドを定義
  □ □ インスタンス変数@ageに1を加算
  □ □ f文字列を使って「〇〇さん、お誕生日おめでとうございます!」を出力

2:Personクラスのインスタンスを生成し、変数personに代入
3:personオブジェクトのname属性を出力
4:personオブジェクトのage属性を出力
5:personオブジェクトのname属性に”ゆかり”を代入
6:変更後のname属性を出力
7:have_birthdayメソッドを呼び出し、その結果を出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

# クラスPersonを定義します
class Person
  # attr_accessorを使用して、ゲッターとセッターを自動生成
=begin
  【穴埋め問題1】
  ここにattr_accessorを使用して、nameとageのゲッターとセッターを自動生成するコードを書いてください。
=end

  # イニシャライザを定義して、初期化時に値を設定できるようにする
=begin
  【穴埋め問題2】
  ここにinitializeメソッドを定義し、引数nameとageをインスタンス変数@nameと@ageにそれぞれ代入するコードを書いてください。
=end

  # 年齢を1歳増やすメソッド
  def have_birthday
=begin
    【穴埋め問題3】
    ここにインスタンス変数@ageに1を加算し、"〇〇さん、お誕生日おめでとうございます!"というメッセージを出力するコードを書いてください。
=end
  end
end

# Personクラスのインスタンスを作成
=begin
【穴埋め問題4】
ここでPersonクラスのインスタンスを作成し、変数personに代入するコードを書いてください。
=end

# ゲッターを使ってnameとageを出力
=begin
【穴埋め問題5】
ここでpersonオブジェクトのnameとageを取得して出力するコードを書いてください。
=end

# セッターを使ってnameを変更
=begin
【穴埋め問題6】
ここでpersonオブジェクトのname属性を変更し、変更後のnameを出力するコードを書いてください。
=end

# 年齢を1歳増やすメソッドを実行
=begin
【穴埋め問題7】
ここでpersonオブジェクトのhave_birthdayメソッドを呼び出して、その結果を出力するコードを書いてください。
=end

以上がこの問題の穴埋めコードです。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。



練習問題の解答と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

# クラスPersonを定義します
class Person
  # attr_accessorを使用して、ゲッターとセッターを自動生成
  attr_accessor :name, :age

  # イニシャライザを定義して、初期化時に値を設定できるようにする
  def initialize(name, age)
    @name = name # インスタンス変数nameに値を設定
    @age = age   # インスタンス変数ageに値を設定
  end

  # 年齢を1歳増やすメソッド
  def have_birthday
    @age += 1
    puts "#{@name}さん、お誕生日おめでとうございます!年齢は#{@age}歳になりました。"
  end
end

# Personクラスのインスタンスを作成
person = Person.new("たかし", 20)

# ゲッターを使ってnameとageを出力
puts "名前: #{person.name}"
puts "年齢: #{person.age}歳"

# セッターを使ってnameを変更
person.name = "ゆかり"
puts "新しい名前: #{person.name}"

# 年齢を1歳増やすメソッドを実行
person.have_birthday

正解コードの解説

今回作成したコードは「アクセスメソッド」を使用したクラスの実装例です。

コードをブロックごとに分割し、初心者向けに解説していきます。

クラスの定義とアクセスメソッド

class Person
  attr_accessor :name, :age
  1. class Person
    クラスPersonを定義しています。Personクラスは名前と年齢を持つ人を表現します。
  2. attr_accessor
    attr_accessorは指定したインスタンス変数に対応するゲッター(取得メソッド)セッター(設定メソッド)を自動生成するRubyの便利な文法です。
    このコードでは、nameageの両方のインスタンス変数に対してゲッターとセッターが生成されます。

    • 例えばperson.nameで名前を取得し、person.name = "新しい名前"で名前を変更することができます。

イニシャライザの定義

  def initialize(name, age)
    @name = name
    @age = age
  end

イニシャライザはPersonクラスのインスタンスが作成されるときに実行されます。

  • 引数nameageを受け取り、それぞれインスタンス変数@name@ageに代入しています。
  • このようにして、オブジェクト生成時に名前と年齢を指定できるようになります。

メソッドの定義

  def have_birthday
    @age += 1
    puts "#{@name}さん、お誕生日おめでとうございます!年齢は#{@age}歳になりました。"
  end

このメソッドは年齢を1歳増やし、お祝いメッセージを表示します。

  • @age += 1で、現在の年齢を1歳増やしています。
  • putsで動的に年齢を組み込んだメッセージを出力します。

インスタンスの作成と操作

person = Person.new("たかし", 20)
puts "名前: #{person.name}"
puts "年齢: #{person.age}歳"
  • インスタンスの作成
    Person.new("たかし", 20)Personクラスのインスタンスを生成し、変数personに代入しています。ここで名前を「たかし」、年齢を20歳として設定しています。
  • ゲッターの使用
    person.nameで名前を取得しperson.ageで年齢を取得しています。それぞれを出力しています。

セッターの使用

person.name = "ゆかり"
puts "新しい名前: #{person.name}"
  • セッターの使用
    person.name = "ゆかり"で名前を「ゆかり」に変更しています。このコードはattr_accessorによって自動生成されたセッターを利用しています。
  • 変更後の名前の取得
    puts "新しい名前: #{person.name}"で変更後の名前を確認しています。

メソッドの呼び出し

person.have_birthday

person.have_birthdayで誕生日を祝うメッセージを表示し、年齢が1歳増えます。

まとめ

このコードではの「アクセスメソッド(attr_accessor)」を使うことで、クラスのインスタンス変数を簡単に操作する方法を学べます。

これによりコードの簡潔さと可読性が向上します。

クラスの作成やメソッドを通じたインスタンスの操作に慣れることは、オブジェクト指向プログラミングを理解する第一歩です。

今回のコードを基に、他のクラスや属性を追加して試してみましょう!

<<前のページ Ruby記事一覧 次のページ>>

この記事への質問・コメント

この記事を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Rubyのテキスト&問題集トップへ戻る
    トップページへ戻る