「オブジェクト指向設計実践ガイド」と言う本を読んでいて、本書を読んでいくとインスタンス変数と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