0
0

More than 1 year has passed since last update.

【Ruby】クラス変数ではなくインスタンス変数を使う場合

Posted at

Rubyの@変数

Rubyには2つの@変数があり、先頭が@のインスタンス変数と先頭が@@変数のクラス変数に分かれる。

インスタンス変数はそれぞれのオブジェクトに属しています。
あるオブジェクトに値がセットされたインスタンス変数は、他のオブジェクトのインスタンス変数には基本的には影響を与えません。

一方で、クラス変数は、オブジェクトごとではなく、クラスごとに与えられます。
クラスから作られたインスタンスは、すべてのインスタンスで参照することができます。
このため、オブジェクトでクラス変数を変更して、意図せずに他のオブジェクトのインスタンス変数を変更してしまうことがあります。

これを、例を示して考えてみます。

シングルトンパターンを実装して@変数を考える

まず、クラス変数が使用される場面として、シングルトンパターンがあります。
シングルトンパターンは、特定のクラスのインスタンスを一つ作り、そのインスタンスをすべてのコードがアクセスできるようにしたい場合に実装されます。

class Singleton
  private_class_method(:new, :dup, :clone)
  def self.instance
    @@instance ||= new
  end
end

# 書籍:Effective Rubyより抜粋

Singletonクラスの中にself.instanceメソッドが定義されています。
これは、インスタンスの存在を確認し、存在しなければ、newメソッドを実行するように定義されています。

また、private_class_methodはpublicなクラスメソッドをprivateなクラスメソッドとして定義できます。
:new, :dup, :cloneをprivateにしているのは、親クラスであるObjectクラスに定義されているメソッドをprivate化して、インスタンスを作る役割をinstanceメソッドに一任しているのがわかります。

では、Singletonクラスを継承するConfigrationクラスDatabaseクラスを定義してみます。

class Configuration < Singleton
end

class Database < Singleton
end

p Configuration.instance
 # => <Configuration:0x0000563c0e4d64a8>
p Database.instance
 # => <Configuration:0x0000563c0e4d64a8>

実際に実装した結果は、どちらもConfigurationクラスから生成されたクラス変数が出力されています。1つのオブジェクトが他のオブジェクトに影響を与えてしまっているのがわかります。

インスタンス変数を使う

考え方としては、すべてのクラスで一意なオブジェクトとして扱われる必要があります。
冒頭で説明した通り、この場合はインスタンス変数を適用することで、解決することができます。

class Singleton
  private_class_method(:new, :dup, :clone)
  def self.instance
    @instance ||= new
  end
end

# 書籍:Effective Rubyより抜粋

クラス変数とインスタンス変数の使用場面には十分注意しましょう!

0
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
0
0