アクセサメソッドでインスタンス変数を簡単に読み書きしよう
学習の目標
本章では、以下の内容を学習します。
- インスタンス変数を読み書きするための基本的な方法を理解する
- アクセサメソッドの概念と利点を学ぶ
- attr_accessor、- attr_reader、- attr_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  endend
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_hp、set_hp、get_mp、set_mpといったメソッドを定義することになります。
Rubyのアクセサメソッド
Rubyでは、インスタンス変数のgetterとsetterを簡単に定義できる機能が用意されています。それがアクセサメソッドです。アクセサメソッドを使うと、先ほどのCharacterクラスは次のように書き換えることができます。
class Character  attr_accessor :name    # nameの読み書きどちらも可能にする
  def initialize(name)    @name = name  endend
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  @nameend
def name=(value)  @name = valueendアクセサメソッドを使うことで、コードが簡潔になり、読みやすくなります。また、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 = "戦士"  endend
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_accessor、attr_reader、attr_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 = "戦士"  endend
hero = Character.new("勇者")puts "名前: #{hero.name}, HP: #{hero.hp}, MP: #{hero.mp}, レベル: #{hero.level}, 職業: #{hero.job}"複数のアクセサメソッドを定義する場合は、カンマで区切って指定するだけです。これにより、コードがさらに簡潔になります。
まとめ
本章では、Rubyにおけるアクセサメソッドについて学びました。以下の内容を理解できたことと思います。
- インスタンス変数にアクセスするには専用のメソッド(getterとsetter)が必要
- Rubyのattr_accessor、attr_reader、attr_writerを使うことで、簡単にアクセサメソッドを定義できる
- 用途に応じて読み取り専用、書き込み専用、読み書き可能なアクセサを選択できる
- 複数のインスタンス変数に対して一度にアクセサメソッドを定義できる
- 必要に応じてカスタムのアクセサメソッドを定義できる
アクセサメソッドを適切に使うことで、オブジェクトの内部データを適切に保護しつつ、必要な操作を提供することができます。これは、オブジェクト指向プログラミングの重要な原則である「カプセル化」の実現に役立ちます。
アクセサメソッドはRubyプログラミングで頻繁に使用される機能ですので、しっかりと理解して活用していきましょう。
Starterプランでより詳しく学習
この先のコンテンツを読むにはStarterプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。