物議を醸し出しがちなパターン
どんなパターン?
アプリの中で、そのclassのインスタンスの存在が1つしか許されない時に使用するパターン
Singleton パターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される
どんな時に使うの?
例えば、設定ファイルの内容のコンテナ。アプリ上で1回だけ読めば良いやつとか
ruby だと、singleton モジュールを使えばOK
require 'singleton'
# 設定ファイルの情報を格納する class
#
class Setting
include Singleton
def initialize
@settings = YAML.load_file("settings.yml")
end
def [](key)
@settings(key)
end
end
# シングルトン は、#instance で、インスタンスを呼び出す
p Setting.instance.object_id # 70341972008800
p Setting.instance.object_id # 70341972008800
Setting.instance['name']
# private method `new' called for SingletonClass:Class (NoMethodError)
クラス変数を使っても同様の実装は可能
require 'singleton'
# 設定ファイルの情報を格納する class
#
class Setting
def self.[](key)
settings(key)
end
def self.settings
@@settings ||= YAML.load_file("settings.yml")
end
end
Setting['name']
どっちが良いかはよくわかってないけど、個人的には明示的にシングルトンであることが判るから、
Singleton
を Mix-in する方が良いと思う
Singleton の問題点
いろいろある
グローバル変数の代わりになってしまう
何かしら状態を持つ Singleton の場合、その状態が色々な所で勝手に変更されてしまうとカオス
→ 状態が変更されるようなクラスは、Singleton にしない方が良い
テストで順序依存が発生しやすい
何かしら状態を持つ Singleton の場合、
次のテストでも、その状態が維持されるため
→ before
で、クラスをリセットする必要がある
コードが密結合になる
Setting.instance
を呼んだ class は、Setting
class と密結合になる
- 密結合はテストの敵
-
Setting
ではない class を使うように変更になった時に、全てのコードを置換する必要が出る
→ 取りに行くのではなく、コンストラクタの引数で、貰うようにする
→ シングルトンにするのは良いけど、色んな class で好き勝手に instance を呼ばないようにする
で、シングルトンは使って良いものなの?
個人的には、上記の意見を意識した上で使うべき理由が見いだせないので、使うことには消極的
ただ、色々な所でコンストラクタの引数で必要なインスタンスを渡すというのもちょっと違和感があるよね...
迷ってます