アクセサメソッドでインスタンス変数を簡単に読み書きしよう

学習の目標

本章では、以下の内容を学習します。

  • インスタンス変数を読み書きするための基本的な方法を理解する
  • アクセサメソッドの概念と利点を学ぶ
  • attr_accessorattr_readerattr_writerの違いと使い方をマスターする
  • インスタンス変数へのアクセス制御方法を習得する

はじめに

オブジェクト指向プログラミングでは、クラスのインスタンス変数に適切にアクセスすることが重要です。前回は、initializeメソッドでインスタンス変数に初期値を設定する方法を学びました。

しかし、インスタンス変数は基本的にクラスの外部からは直接アクセスできません。そこで今回は、インスタンス変数を読み書きするための便利な方法であるアクセサメソッドについて学んでいきます。

アクセサメソッドを使うと、インスタンス変数の値を簡単に取得したり変更したりできるようになります。これは、オブジェクト指向プログラミングにおける重要な概念の一つです。

ファイルの準備

まずは、accessor.rbというファイルを作成しましょう。VS Code で新しいファイルを作成し、これから書いていくコードを保存していきます。

インスタンス変数を読み書きする基本的な方法

オブジェクト指向プログラミングでは、インスタンス変数はクラスの外部から直接アクセスすることができません。そのため、インスタンス変数の値を取得したり設定したりするためには、専用のメソッドが必要になります。

まずは、前回作ったCharacterクラスで名前を取得したり、変更したりする例を見てみましょう。

class Character
def initialize(name)
@name = name
end
# 名前を取得するメソッド(getter)
def get_name
@name
end
# 名前を設定するメソッド(setter)
def set_name(name)
@name = name
end
end
hero = Character.new("勇者")
puts hero.get_name # 勇者と表示される
hero.set_name("勇者マサシ")
puts hero.get_name # 勇者マサシと表示される

このコードでは、インスタンス変数@nameの値を取得するためのget_nameメソッドと、値を設定するためのset_nameメソッドを定義しています。これらのメソッドは一般的に次のように呼ばれます。

  • getter:インスタンス変数の値を取得するメソッド
  • setter:インスタンス変数に新しい値を設定するメソッド

このように、インスタンス変数の数が増えるにつれて、それぞれにgetterとsetterを定義する必要があります。これは次第に面倒になってきますね。例えば、@hp@mpなどの変数が増えれば、それぞれに対してget_hpset_hpget_mpset_mpといったメソッドを定義することになります。

Rubyのアクセサメソッド

Rubyでは、インスタンス変数のgetterとsetterを簡単に定義できる機能が用意されています。それがアクセサメソッドです。アクセサメソッドを使うと、先ほどのCharacterクラスは次のように書き換えることができます。

class Character
attr_accessor :name # nameの読み書きどちらも可能にする
def initialize(name)
@name = name
end
end
hero = Character.new("勇者")
puts hero.name # 勇者と表示される(getterとして使用)
hero.name = "勇者マサシ" # setterとして使用
puts hero.name # 勇者マサシと表示される

attr_accessor :nameという一行で、nameメソッド(getter)とname=メソッド(setter)の両方が自動的に定義されます。これにより、hero.nameでインスタンス変数@nameの値を取得でき、hero.name = "勇者マサシ"でその値を変更できるようになりました。

このattr_accessorは非常に便利で、Rubyプログラマーがよく使う機能の一つです。内部的には、以下のようなメソッドが自動生成されています。

# attr_accessor :name と書くと、以下のメソッドが自動的に定義される
def name
@name
end
def name=(value)
@name = value
end

アクセサメソッドを使うことで、コードが簡潔になり、読みやすくなります。また、Rubyらしい書き方ができるというメリットもあります。

読み取り専用と書き込み専用のアクセサメソッド

状況によっては、インスタンス変数の値を読み取るだけで変更は許可しない、あるいはその逆のケースがあります。例えば、キャラクターのHPは表示(読み取り)だけを許可して、外部からの直接変更は許可しないといった場合です。

Rubyでは、このような場合に対応するために、attr_reader(読み取り専用)とattr_writer(書き込み専用)というアクセサメソッドも用意されています。

次の例で、それぞれの違いを見てみましょう。

class Character
attr_reader :hp # hpは読み取りだけ可能
attr_writer :job # jobは書き込みだけ可能
attr_accessor :name # nameは読み書き両方可能
def initialize(name)
@name = name
@hp = 100
@job = "戦士"
end
end
hero = Character.new("勇者")
puts hero.hp # 100と表示される
# hero.hp = 200 # エラー:書き込みはできない
hero.job = "魔法使い" # 書き込みはできる
# puts hero.job # エラー:読み取りはできない
puts hero.name # 勇者と表示される
hero.name = "勇者マサシ" # どちらもできる
puts hero.name # 勇者マサシと表示される

この例では、hpは読み取り専用、jobは書き込み専用、nameは読み書き両方可能に設定しています。コメントアウトされている行は、実行するとエラーになる操作です。

色々出てきましたので、混乱しないように、attr_accessorattr_readerattr_writerの違いを整理しておきましょう。

  • attr_reader:読み取り専用のメソッド(getter)を定義する
  • attr_writer:書き込み専用のメソッド(setter)を定義する
  • attr_accessor:読み書き両方のメソッド(getterとsetter)を定義する

これらのアクセサメソッドを適切に使い分けることで、インスタンス変数へのアクセス制御を行うことができます。

例えば、ゲームのスコアなど勝手に変更されては困る値はattr_readerにして、読み取りのみを許可するといった使い方ができます。

また、複数のインスタンス変数に対して同時にアクセサメソッドを定義することもできます。

class Character
attr_reader :hp, :mp, :level # 複数の読み取り専用変数
attr_accessor :name, :job # 複数の読み書き可能変数
def initialize(name)
@name = name
@hp = 100
@mp = 50
@level = 1
@job = "戦士"
end
end
hero = Character.new("勇者")
puts "名前: #{hero.name}, HP: #{hero.hp}, MP: #{hero.mp}, レベル: #{hero.level}, 職業: #{hero.job}"

複数のアクセサメソッドを定義する場合は、カンマで区切って指定するだけです。これにより、コードがさらに簡潔になります。

まとめ

本章では、Rubyにおけるアクセサメソッドについて学びました。以下の内容を理解できたことと思います。

  • インスタンス変数にアクセスするには専用のメソッド(getterとsetter)が必要
  • Rubyのattr_accessorattr_readerattr_writerを使うことで、簡単にアクセサメソッドを定義できる
  • 用途に応じて読み取り専用、書き込み専用、読み書き可能なアクセサを選択できる
  • 複数のインスタンス変数に対して一度にアクセサメソッドを定義できる
  • 必要に応じてカスタムのアクセサメソッドを定義できる

アクセサメソッドを適切に使うことで、オブジェクトの内部データを適切に保護しつつ、必要な操作を提供することができます。これは、オブジェクト指向プログラミングの重要な原則である「カプセル化」の実現に役立ちます。

アクセサメソッドはRubyプログラミングで頻繁に使用される機能ですので、しっかりと理解して活用していきましょう。

このセクションは有料サブスクリプションへの登録、またはログインが必要です。完全なコンテンツにアクセスするには、料金ページ(/pricing)をご覧ください。購入済みの場合は、ログインしてください。

Starterプランでより詳しく学習

この先のコンテンツを読むにはStarterプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。

作成者:とまだ
Previous
initializeメソッドでインスタンスの初期設定をしよう