56
47

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.

物議を醸し出しがちなパターン

どんなパターン?

アプリの中で、そのclassのインスタンスの存在が1つしか許されない時に使用するパターン

Singleton パターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される

どんな時に使うの?

例えば、設定ファイルの内容のコンテナ。アプリ上で1回だけ読めば良いやつとか

ruby だと、singleton モジュールを使えばOK

singleton.rb
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)

クラス変数を使っても同様の実装は可能

singleton.rb
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 を呼ばないようにする

で、シングルトンは使って良いものなの?

個人的には、上記の意見を意識した上で使うべき理由が見いだせないので、使うことには消極的
ただ、色々な所でコンストラクタの引数で必要なインスタンスを渡すというのもちょっと違和感があるよね...

迷ってます

参考

56
47
3

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
56
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?