1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

クラス変数じゃなくてクラスインスタンス変数を使う

Last updated at Posted at 2018-12-18

クラス変数は使わないほうがいいとRubocopを始めいろいろな人から助言を受けます。

クラス変数を持つクラスを継承して使う際に、次のようにちょっと困ったことが起こります。

# 親クラス (クラス変数を持っている)
class Base
  @@quux = 'quux'

  def self.quux
    @@quux
  end

  def self.quux=(value)
    @@quux = value
  end
end

# 子クラスその1
class Foo < Base
end

# 子クラスその2
class Bar < Base
end

# クラス変数を表示 (初期値が見える)
p Foo.quux # => "quux"
p Bar.quux # => "quux"

# Fooのクラス変数を変更する
Foo.quux = 'hi'

# クラス変数を表示
p Foo.quux # => "hi" 変更したとおりに変わっている
p Bar.quux # => "hi" Barのクラス変数までも変わっている

継承した片方のクラスでクラス変数を変更すると、同じく継承したもう一方のクラスのクラス変数までもかわってしまいます。

意図的に使うならともかく、大抵の場合、おそらく期待しない動作です。

クラスインスタンス変数

クラス変数の代わりに、クラスインスタンス変数を使うように勧められます。

# 親クラス (クラスインスタンス変数を持っている)
class Base
  def self.quux
    @quux
  end

  def self.quux=(value)
    @quux = value
  end

  def self.inherited(klass)
    klass.quux = 'quux' # 共通の初期値を設定
  end
end

# 子クラスその1
class Foo < Base
end

# 子クラスその2
class Bar < Base
end

# クラスインスタンス変数を表示 (初期値が見える)
p Foo.quux # => "quux"
p Bar.quux # => "quux"

# Fooのクラスインスタンス変数を変更する
Foo.quux = 'hi'

# クラスインスタンス変数を表示
p Foo.quux # => "hi" 変更したとおりに変わっている
p Bar.quux # => "quux" Barのクラスインスタンス変数か影響を受けていない

なお、クラスインスタンス変数に対するアクセサは、次のようにすれば、インスタンス変数に対するものと同様に簡単に定義できます。

class Base
  class << self
    attr_accessor :quux
  end
end
1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?