シングルトンパターンを使う時の条件とは

#はじめに
タイトルにも書いてあるように、シングルトンパターンを使う時の条件を備忘録としてまとめます。

#シングルトンパターンとは
デザインパターン(ソフトウェア開発における設計パターン)の一つであり、`シングルトン`を使って定義します。
そして、シングルトンパターンは`インスタンスが1個しか生成されないことを保証したい時`に使います。

シングルトンの代表例として、`UserDefaults`や`UIApplication`などがあります。

#シングルトンの書き方
swiftでのシングルトンの書き方は、`クラス`に以下のコードを記述するだけです。

```swift
class Hogehoge {
  // 初回アクセスのタイミングで初期化
  static let shared = Hogehoge()
  // 外部からのインスタンス生成を禁止する
  private init() {}
}

// このようにして呼び出すことができる
Hogehoge.shared
```
因みにですが、`struct`に対してシングルトンパターンは用いることが出来ません。

`Copy on Write (CoW)`によって`暗黙的にコピーを発生させてしまう`からです。

```swift
struct Fugafuga {
    var str = "original"
    static let shared = Fugafuga()
}

var fugafuga = Fugafuga.shared
// ここでCoWによってコピーが発生し、Fugafuga.sharedとは別物になってしまう
fugafuga.str = "copy"

print(fugafuga.str) // copy
print(Fugafuga.shared.str) // original

```
このようにコピーが発生してしまえば、`インスタンスが1個`では無くなってしまい
シングルトンパターンの要件を満たせないからです。

#使う時の条件とは
先ほど、シングルトンパターンを使用する場面は`インスタンスが1個しか生成されないことを保証したい時`と書きましたが...自分にはあまりピンと来ません。

じゃあ、そういう場面とは？という感じで結局、どこで使用するか分かりません。
自分は`あらゆる場所から呼べる便利さ`から何となく使っている感じでした。

##・便利だが、危険でもある
しかし、`あらゆる場所から呼べる便利さ`ですが危険性もあります。

swiftの機能の大部分は、`オブジェクト指向`という考え方で設計されています。

この設計方法には3つの原則があり、その中の1つ「`カプセル化`」がシングルトンパターンと`真逆の考え方`なんですね。

##・カプセル化とシングルトンパターン
カプセル化を意識すると、`意図していない場所で値が好きな様に書き換えられてしまうことを防ぐ`ことができます。

例えば、このようなコードがあったとします。

```swift
class Hogehoge {
  var str = "Hello World!"
}
```
外部で`Hogehogeクラスのインスタンス`を作成した場合、今のままだとクラス内に宣言されている`strプロパティ`にアクセス出来てしまいます。

つまり、下記のように外部から好きな値に書き換えることが可能になります。

```swift

class Hogehoge {
  var str = "Hello World!"
}

let hogehoge = Hogehoge()
print(hogehoge.str) // Hello World!
hogehoge.str = "Goodbye World!"
print(hogehoge.str) // Goodbye World!
```
では、カプセル化を意識して先ほどのコードを改修してみましょう。

```swift
class Hogehoge {
  private var str = "Hello World!"
}

let hogehoge = Hogehoge()
print(hogehoge.str) // エラー
hogehoge.str = "Goodbye World!" // エラー
print(hogehoge.str) // エラー
```
`private`をvarの前に付けました。

こうする事によって、`外部からアクセスしようとしてもエラーになるので外部から値を好きな様に書き換えられてしまう`ことが無くなりました。

しかし、`シングルトンパターン`は色んな場所で呼び出せてしまうので`思わぬ場面で大切なデータを書き換えてしまった`等の危険性があります。

なので、`適した場面で使用しなくてはいけません`。

#シングルトンパターンの正しい使い方
Appleドキュメントで書かれていました。(やはり、公式ドキュメントを読むのが良き)

>「シングルトンを使用して、グローバルにアクセス可能なクラスの共有インスタンスを提供します。サウンド効果を再生するオーディオチャンネルや、HTTPリクエストを行うネットワークマネージャのように、アプリ全体で共有されているリソースやサービスへの統一されたアクセスポイントを提供する方法として、独自のシングルトンを作成することができます。」
(引用: [Managing a Shared Resource Using a Singleton | Apple Developer Document](https://developer.apple.com/documentation/swift/cocoa_design_patterns/managing_a_shared_resource_using_a_singleton))

##上記のドキュメントを読んで自分なりに解釈する

例えば、ログイン機能をアプリに実装しようと思い、`新規登録画面(以下、画面A)`と`ログイン画面(以下、画面B)`を作ろうと思いました。

**1.早速、実装しようとするも画面によってログインに関するインスタンスを生成するのは面倒だし、無駄にメモリを消費してしまう等の問題が...。**

↓

**2.なら`ログイン機能を管理するクラス`を作った方がいいな。**

↓

**3.シングルトンパターンを`使用しない`場合。`ログイン機能を管理するクラスのインスタンス`を画面A・Bそれぞれに対して生成しなくてはならないし、更にそれぞれで何か変更を加えた際に不整合が起こる可能性があり、`管理しにくい`。**

**シングルトンパターンを`使用する`場合。そこで、アプリ内で`ログイン機能を管理するクラスのインスタンスは1個のみ`を保証するシングルトンパターンを使用すれば、`ログイン機能を管理するクラス`が統一されているので不整合が起きにくく、更にはソースコードの可読性が向上し、`管理しやすくなる`。**

ということでしょうか？
#おわりに
まだまだ、まとめた今でもシングルトンパターンを使えるか不安ですが
とりあえず知識は深まりました。

因みに自分の現在開発しているアプリでは、先ほどの`ログイン機能を管理するクラス`の他に`API通信を行うクラス`もシングルトンパターンを使用しています。

メンターによると、API通信を行うクラスはシングルトンパターンにするのが主流だそうです。

#参考記事
[【Swift】Singleton パターンってどういう時に使うの？](https://www.hfoasi8fje3.work/entry/2018/04/16/121711)
[Swift におけるシングルトン・staticメソッドとの付き合い方](https://medium.com/swift-column/singleton-398078bcc58d)