クラス変数("@@")やめとけってよ

クラス変数("@@")使う人あんまりいないと思うけど、グローバル変数と同じようなもんだから使うなよっていう話。

Effective Ruby

Effective Ruby

項目15 クラス変数よりもクラスインスタンス変数を使うようにしよう

クラス変数を使ってSingletonを実装してみる

一見いい感じ。

class Singleton
  private_class_method(:new, :dup, :clone)

  def self.instance
    @@single ||= new
  end
end

でもサブクラスだとNG

全てのサブクラス間で共有されてしまう。

class Configuration < Singleton; end
class Database < Singleton; end

>> Configuration.instance
#<Configuration:0x00007fed1a890c88>

# NG: Configurationになっちゃう
>> Database.instance
#<Configuration:0x00007fed1a890c88>

解決方法:クラスインスタンス変数

「クラスメソッド内でインスタンス変数?」となるかもしれないが、クラスもオブジェクト。

class Singleton
  private_class_method(:new, :dup, :clone)

  def self.instance
    # @@ -> @に変更するだけ
    @single ||= new
  end
end

おまけ

スレッドを考慮すると上記実装では不十分。標準ライブラリのSingletonを使うと良い。

require "singleton"

class Configuration
  include Singleton
end

覚えておくべき事項

  • クラス変数よりもインスタンス変数を使うようにしよう。
  • クラスはオブジェクトなので、専用のプライベートなインスタンス変数セットを持っている。