LoginSignup
2
0

More than 3 years have passed since last update.

インスタンス変数 と attr_* について

Last updated at Posted at 2020-08-27

概要

便利な機能であっても、少なからずデメリットも発生することがあると思います。

なので使う側はメリット・デメリットのバランスを判断して、適切に実装を行うことができるようになる必要があるのでは?
と思い、記事にまとめてみました。

実際に保守しづらさ のほうが勝っているケースがあり、改めて必要性があるのか?を検討するための参考になればと思います

まずattr_*を使うとどうなるか?

attr_reader :name とすることで引数の名称でgetterメソッドが定義されます

def name
  @name
end

attr_writer :name とすることで引数の名称でsetterメソッドが定義されます

def name=(val)
  @name = val
end

attr_accessor :name はreaderとwriterの複合メソッドです

通常、インスタンス変数はインスタンスの内部にて @hoge でアクセスできるものがpublicでメソッドが定義されるため外部からインスタンス変数の値を触ることができるようになります。

この時privateを使用することによってprivateでメソッドを定義させることも可能です。

private
attr_reader :hoge

メリットとデメリットについて

メリット

外部からの呼び出し

本来の用途である、publicメソッドとして切られるため外部からの使用ができます
※privateにもできます

ここは皆さんご存知のとおりでしょう。

改修のしやすさ

class Hoge
  private
  attr_accessor :hoge

  def initialize(hoge:)
    @hoge = hoge
  end

  def connect
    Service.call(hoge: hoge) # <- ココ
  end
end

このような実装になっているとき、

def hoge
  @hoge + 1
end

のように改修する必要が出たときにオーバーライドすることで修正はしやすくなります。

デメリット

スコープの意識

publicprivateかなどを正しく考える必要がでる

メソッドの定義

メソッドを不用意に定義することで、メソッド名が競合してしまう可能性

可読性

  • オーバーライドできるということは、メソッドがオーバーライドされていないか?を確認する必要がでる => 可読性が下がる

class Hoge
  include Hoge::XXXable
  include Hoge::ZZZable

  private
  attr_accessor :hoge

  def initialize(hoge:)
    @hoge = hoge
  end

  def connect
    Service.call(param: param)
  end
end

module Hoge::XXXable
  include ::YYYable
  def param
    {
      hoge: hoge # <- ココ
    }
  end
end

このように対象のクラスにincludeされる前提のモジュール(切り出しモジュール)に対して
インスタンス変数を参照しているだけだがメソッド呼び出しにできます

これが

module Hoge::XXXable
  include ::YYYable
  def param
    {
      hoge: @hoge # <- ココ
    }
  end
end

となっていれば「includeして読み込まれるクラスのインスタンス変数をセットしている」とモジュール内のソースを見るだけでパッとわかります。
※インスタンス変数をほかのクラスやモジュールで直接触るようなものは書きたくない という意味であれば気持ちは分かりますが。

しかし、これがattrのgetterメソッドとなっていることによって、XXXableのモジュールを見るだけだと、hogeは一体どこで定義されているメソッドなのか?が分かりません。
そのため下記のどこか?を探す作業が発生してしまいます。
- XXXable内で定義されているか
- XXXableにてincludeやextendされているモジュールの中
- XXXableをincludeしている側のクラスやモジュール
- XXXableをincludeしている側のクラスやモジュールが読み込んでいるモジュール

結論

メリットで挙げた、保守がしやすくなる というのは上書きが簡単 という意味では当てはまりますが、
その必要性が現段階で想定できないようなケースであれば、逆に 保守がしにくく なっていないでしょうか?

使う際には こうしたデメリットが大きくなるケースではないか? を今一度考えながら使用するかどうかを検討していき
よりよいプログラムを書いていきたいなと思います

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0