Rubyではインスタンス変数を直接使うよりattr_readerを使うべき2つの理由

「オブジェクト指向設計実践ガイド」と言う本を読んでいて、本書を読んでいくとインスタンス変数とattr_readerメソッドの違いとか使い道について興味を持ったので、まとめていきます。

最終的な結論は、「attr_readerメソッドを使った方が何かしらと便利」となったわけですが、その道なりをまとめていきます。

インスタンス変数とattr_readerの決定的な違いとは?

インスタンス変数とattr_readerの決定的な違いは、インスタンスの外側から参照できるかどうかと言うのが主に挙げられる。

例えば、以下のコードを見てみよう。

class Gear
def initialize(cog, chain)
@cog = cog
@chain = chain
end
end
gear = Gear.new(2,10)
puts gear.cog
# undefined method `cog' for #<Gear:0x000055c7f997ae20 @cog=2, @chain=10> (NoMethodError)

上記のコードは間違いで、おそらくgearオブジェクトの@cog変数を参照しようとして書いたと思われるが、@cogの様なインスタンス変数はオブジェクトの外側から直接参照できないようになっている。

しかし、Gearクラスに以下の様にcogメソッドを用意してあげることで、@cog変数を取り出す事ができる。(この表現は厳密には違う)

class Gear
attr_reader :cog
#    ↓と全く同じ
#   def cog
#      @cog
#   end
def initialize(cog, chain)
@cog = cog
@chain = chain
end
end
gear = Gear.new(2,10)
puts gear.cog  # 2

上記の例が、Rubyにおけるインスタンス変数とattr_readerの違いとして良く挙げられるものだろう。

attr_readerを使うべき2つの理由

しかし、実際は以下の2つの点でインスタンス変数よりもattr_readerを使うべきだと考えている。

  • attr_readerを使うと変更が容易になる
  • タイプミスの時にミスに気づきやすい

以下は、詳しく説明していく。

attr_readerを使うと変更が容易になる

以下のコードは、2つのインスタンス変数に対してattr_readerを使っているものだ。

class Gear
attr_reader :cog, :chain
def initialize(cog, chain)
@cog = cog
@chain = chain
end
def calc
chain * cog
end
end

上記のコードのcalcメソッドを以下の様に、メソッドではなくてインスタンス変数を直接参照する場合でも、問題なく動く。

    def calc
@chain * @cog
end

しかし、懸念すべき点は、「cogメソッドの動きを変えたい」と言う時にインスタンス変数だと変更の際に色々な事を考える必要が出てくるが、attr_readerメソッドを使ってcogメソッドを定義しておけば、cogメソッド内をいじるだけで変更できる、と言う強みがある。

例えば、以下の様に変更するのが用意だ。(下記の例はまだ単純なクラス構造なので良いが、@cogが使われる場面が多くなるほどattr_readerのありがたさが身に染みる。

class Gear
attr_reader  :chain
def initialize(cog, chain)
@cog = cog
@chain = chain
end
def cog
@cog * 100
end
def calc
chain * cog
end
end

ReratedPosts

RubyやRailsをプロジェクト毎に入れて管理する方法
RubyでGUIアプリ(デスクトップアプリ)を作るための環境構築
Rubyで文字列の先頭や末尾にある空白文字とか全角スペースを削除する方法
Rails5で作ったアプリをHerokuでデプロイする手順