Rubyデザインパターン 9日目 : Singleton

Rubyデザインパターン学習のために、自分なりに読書の結果をまとめていくことに決めました。第9日目はSingletonです。(http://www.amazon.co.jp/gp/product/4894712857/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4894712857&linkCode=as2&tag=morizyun00-22)

![スクリーンショット 2015-07-27 11.25.28.png](https://qiita-image-store.s3.amazonaws.com/0/80075/d68a4010-c177-4ef5-2f2e-899a76c76cb6.png)


# **<i class="fa fa-pencil"></i>　9日目Singleton**
オブジェクト生成は一般的に負荷のかかる作業です。
生成するオブジェクト数を制限したり、ひとつに限定したいときなどに使うパターンがSingletonです。
シングルトンクラスのオブジェクト生成を、シングルトンクラス自身が提供することになります。

# **<i class="fa fa-code"></i>Singleton サンプルコード**

```rb

class SimpleLogger
  attr_accessor :level

  ERROR = 1
  WARNING = 2
  INFO = 3

  def initialize
    @log = File.open("log.txt", "w")
    @level = WARNING
  end

  def error(msg)
    @log.puts(msg)
    @log.flush
  end

  def warning(msg)
    @log.puts(msg) if @level >= WARNING
    @log.flush
  end

  def info(msg)
    @log.puts(msg) if @level >= INFO
    @log.flush
  end
end
logger = SimpleLogger.new
logger.level = SimpleLogger::INFO # このインスタンスを持ち回りながら使う

logger.info('1番目の処理を実行')
logger.info('2番目の処理を実行')
```
この状態で常に同じオブジェクトをプログラム内で扱いたいとき、いろんなところで`logger`オブジェクトを使い回さないといけません。
そして、`SimpleLogger.new`をするたびに異なったオブジェクトができてしまいます。

この問題点を解決するために、これからシングルトンを作ってみましょう。

```rb
class SimpleLogger
  #
  #
  #
  @@instance = SimpleLogger.new

  def self.instance
    return @@instance
  end
end

logger1 = SimpleLogger.instance
logger2 = SimpleLogger.instance
logger3 = SimpleLogger.new
logger1.object_id # => 70354806787840 same
logger2.object_id # => 70354806787840 same
logger3.object_id # => 70354806787560 other
```
`@@instance`にはすでに`SimpleLogger`インスタンスが作成されて入っています。
こういった実装にすることで、`.instance`メソッドからインスタンスを呼び出す限り、必ず同じオブジェクトを参照できることになります。

この状態では、まだ完全にシングルトンとは呼べません。
なぜなら、まだ`new`メソッドによりオブジェクトを複数作れてしまうからです。

```rb
class SimpleLogger
  @@instance = SimpleLogger.new

  def self.instance
    return @@instance
  end
  private_class_method :new
end

SimpleLogger.new # => error
```

これでシングルトンは完成となります。
`new`メソッドはもはや`SimpleLogger`クラス内でしか使用できなくなりました。

## <i class="fa fa-diamond"></i> Let's Ruby!!!

```rb

require 'singleton'

class SimpleLogger
  include Singleton # クラス変数を定義して、シングルトンインスタンスで初期化して、self.instanceというクラスレベルメソッドを作りnewメソッドをプライベート化してくれる
  #
  #
  #
end

SimpleLogger.new # => private method `new' called for SimpleLogger:Class (NoMethodError)
SimpleLogger.instance # => #<SimpleLogger:0x007f97b9a7e510>
```

**なんということでしょう。**
`include Singleton`をするだけで、Singletonを作ることができます。
このモジュール型では**遅延型インスタンス化**を実現しています。

### <i class="fa fa-lightbulb-o"></i> 積極的・遅延型インスタンス化とは
- 積極的インスタンス生成 ： 実際に必要になる前にインスタンスを生成する(クラス変数型
- 遅延型インスタンス生成 ： 必要になった時にインスタンスを生成する(モジュール型

先ほどのモジュール型だと、`.instance`メソッドが呼ばれた時にインスタンスを生成するので後者です。
どちらがいいかは時と場合によるでしょう。

##<i class="fa fa-puzzle-piece"></i> シングルトンとしてのモジュール

```rb
module ModuleBasedLogger
  ERROR = 1
  WARNING = 2
  INFO = 3
  @@log = File.open('log.txt', 'w')
  @@level = WARNING
  def self.error(msg)
    @@log.puts(msg)
    @@log.flush
  end

  def self.warning(msg)
    @@log.puts(msg) if @@level >= WARNING
    @@log.flush
  end

  def self.info(msg)
    @@log.puts(msg) if @@level >= INFO
    @@log.flush
  end

  def self.level=(new_level)
    @@level = new_level
  end
end

ModuleBasedLogger.level = 3
ModuleBasedLogger.info('お知らせがあります〜〜〜')
```

こういった形で、シングルトン機能を実現できます。
モジュールベースで作ることで、「これはメソッドの入れ物として作っていて、インスタンス化するために作ったオブジェクトではない」と明示的にできる意図があります。



# **<i class="fa fa-star"></i>　まとめ**

Singletonは諸刃の剣のようなものに例えられます。
メリットは、ただ一つだけの何かが存在するということを保証してくれます。これは、シングルトンが一つのオブジェクト(インスタンス)しか作れないようにしてくれているからです。

▼シングルトンの大きな特徴2つおさらい
 1. オブジェクト(インスタンス)が一つしか存在しない
 2. そのオブジェクト(インスタンス)へのアクセスはどこからでも行える(※ただし、グローバル変数のような使い方は絶対にしないこと)

実例では、WEBrick、Rake、Railsでよく使われているそうです。ソースコードを漁ると出会うことができるでしょう。

## 参照
http://www.nulab.co.jp/designPatterns/designPatterns2/designPatterns2-1.html