Swiftで覚えるデザインパターンその3

# はじめに
Swiftで覚えるデザインパターン第3弾です。

1. **[Swiftで覚えるデザインパターン](https://qiita.com/ta9yamakawa/items/4f97855be4bd0698d166)**
 1. Strategy
 1. Observer
 1. Decorator
 1. Factory Method
 1. Abstract Factory
 1. Singleton
1. **[Swiftで覚えるデザインパターンその2](https://qiita.com/ta9yamakawa/items/a3e72372df7b2922315b)**
 1. Command
 1. Adaptor
 1. Facade
 1. Template Method
1. **Swiftで覚えるデザインパターンその3** ← 今ココ
    1. Iterator
    1. Composite
    1. State
    1. Compound

# Iteratorパターン
## 概要
集約したいくつかのオブジェクト（配列やコレクション）　＝　`アグリゲート`に順次アクセスできるようにする。

## 試しに作ったもの
大学の学部生と修士生の履歴書のデータをボタン一つで一括表示するような画面を作りました。

|<img width="150" alt="IteratorSampleApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/0ba26e85-4f81-b773-55e8-524fe4b30433.png">|
|:--|

※長くなるので最後の方切れてます。
<img width="300" alt="IteratorSampleAppResult.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/20bd07a4-dcbf-9f78-0ef8-9f474a231578.png">

## クラス図
`Iterator`には各要素にアクセスできるようなメソッドを定義します。
ひとまず、次の要素を返す`next()`と次の要素があるかを調べる`hasNext()`を定義しています。
必要によっては、一番最初の要素を返す`first()`や逆に最後の要素を返す`last()`とかを定義しても良さそうです。

Iteratorが全てのアグリゲートに統一した方法でアクセスする方法を定義すれば、アグリゲートの形式を考える必要がなくなります。

また、新しいAggregateを作ってもそれ用のIteratorを追加し、同様にViewControllerでこれまでのAggregateと同様に呼び出せば良いので改修するのも簡単にできます。

ちなみに今回はModelを定義していますが、必ずしもIteratorパターンに必要なものではありません。

|<img width="650" alt="Iterator.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/d8653f30-cf04-30ef-d199-705224a57f21.png">|
|:--|


## 実装

```swift:Modelの定義
protocol StudentModel {
    /// 氏名
    var name: String { get }
    /// 年齢
    var age: Int { get }
    /// 大学名
    var universityName: String { get }
    /// 志望動機
    var motivation: String { get }
}

// Masterの場合も同様
struct BachelorModel: StudentModel {
    /// 氏名
    let name: String
    /// 年齢
    let age: Int
    /// 大学名
    let universityName: String
    /// 志望動機
    let motivation: String
}
```

```swift:Aggregate周り
protocol Aggregate {
    /// イテレーターを作成
    func createIterator() -> Iterator
}

// Masterも同様なものを作成する
class Bachelor: Aggregate {
    var models = [BachelorModel]()

    init() {
        models.append(BachelorModel(name: "山田",
                                    age: 22,
                                    universityName: "〇〇大学",
                                    motivation: "頑張ります！"))
        // 同様にいくつか追加 
    }

    func createIterator() -> Iterator {
        return BachelorIterator(bachelor: self)
    }
}
```

```swift:Iterator周り
protocol Iterator {
    /// 次の要素があるか
    func hasNext() -> Bool
    /// 次の要素を取得する
    func next() -> StudentModel?
}

// Masterの場合も同様
class BachelorIterator: Iterator {
    private var bachelor: Bachelor?
    private var index = 0

    init(bachelor: Bachelor) {
        self.bachelor = bachelor
    }

    func hasNext() -> Bool {
        guard let models = bachelor?.models else {
            return false
        }
        return !(index >= models.count)
    }

    func next() -> StudentModel? {
        guard let models = bachelor?.models else {
            return nil
        }

        let bachelor = models[index]
        index += 1
        return bachelor
    }
}
```

```swift:IteratorViewController.swift
class IteratorViewController: UIViewController {
    /// 学部生
    private let bachelor = Bachelor()
    /// 修士生
    private let master = Master()

    @IBAction func didTapListUpButton(_ sender: Any) {
        listUpStudents()
    }

    /// 学部生と修士学生をリストアップ
    func listUpStudents() {
        let bachlorIterator = bachelor.createIterator()
        let masterIterator = master.createIterator()
        listUpStudents(from: bachlorIterator)
        listUpStudents(from: masterIterator)
    }

    /// 学生をリストアップ
    func listUpStudents(from iterator: Iterator) {
        while iterator.hasNext() {
            guard let model = iterator.next() else {
                return
            }

            print(model.name + " " + String(model.age) + "歳です。\n")
            print(model.universityName + "出身です。\n")
            print(model.motivation)
            print("==============")
        }
    }
}
```

# Compositeパターン
## 概要
オブジェクトを**ツリー構造**に構成して扱う。
このとき、クライアントは個別の**オブジェクト**と**オブジェクトのコンポジション**を同じものとして扱うことができる

登場人物は以下の3つ

- `Component`：コンポジションの全てのオブジェクト用のインターフェースを定義する
- `Composite`：子要素を持つコンポーネントの振る舞いを定義し、子要素を格納する
- `Leaf`：子要素を持たない要素。コンポジション内の全ての要素の振る舞いを実装する

## 試しに作ったもの
ツリー構造になりそうなもので浮かんだのが家系図だったので、家系図っぽくなるような家族のリストアップを行う画面を作りました。
画面自体には何かを表示すると言うことはせず、画面を開いた時に家族の一覧をコンソールに表示するようなものとなります。

田中家は通常パターンで`家族-メンバー`の関係で表示するようにしています。
鈴木家は、佐藤家から**婿入りしてきたメンバー**を盛り込んでいるので、階層化されています。
<img width="200" alt="CompositeSampleAppResult.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/460bb50f-802b-3702-fc94-a27fbee2ceb8.png">

正直作った時にもっとわかりやすい例があったなと後悔...

## クラス図
`CompositeViewController`がクライアントとしてComponentにアクセスします。
クライアントは、`Family（Composite）`にも、`Person（Leaf）`にもアクセスすることができます。

Componentをインターフェースとして定義し、Family、Personの両方でComponentを実装します。
CompositeであるFamilyの方では、`listUp()`を再起的に呼び出すことで、要素がLeafであればLeaf用のリストアップを行い、要素が再度Compositeであれば再度メソッドを呼び出すようにします。

|<img width="650" alt="Composite.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/72d3d2b7-59b9-a558-4d61-5b1c784a2ecb.png">|
|:--|

## 実装

```swift:Component
protocol Component {
    func listUp()
}
```
```swift:CompositeとLeaf
/// 家系（Compositeに該当する）
class Family: Component {
    /// 全ての家族
    var family = [Component]()
    /// 名字
    private let familyName: String

    init(familyName: String) {
        self.familyName = familyName
    }

    func listUp() {
        print("\(familyName)家\n")

        for person in family {
            person.listUp()
        }
    }
}

/// 個人（leafに該当する）
class Person: Component {
    /// 氏名
    private let name: String

    init(name: String) {
        self.name = name
    }

    func listUp() {
        print(name)
    }
}
```
```swift:CompositeViewController.swift
class CompositeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        setupFamily()
    }

    /// 家族の設定
    func setupFamily() {
        let tanakaFamily = Family(familyName: "田中")
        tanakaFamily.family.append(Person(name: "田中一郎"))
        tanakaFamily.family.append(Person(name: "田中二郎"))
        tanakaFamily.family.append(Person(name: "田中三郎"))

        let suzukiFamily = Family(familyName: "鈴木")
        suzukiFamily.family.append(Person(name: "鈴木一花"))
        suzukiFamily.family.append(Person(name: "鈴木ニ菜"))
        suzukiFamily.family.append(Person(name: "鈴木三春"))
        // 婿入り
        let satoFamily = Family(familyName: "佐藤(旧姓)")
        satoFamily.family.append(Person(name: "佐藤一"))
        suzukiFamily.family.append(satoFamily)

        tanakaFamily.listUp()
        print("=============")
        suzukiFamily.listUp()
        print("=============")
    }
}
```

# Stateパターン
## 概要
オブジェクトの内部状態が変化した時、オブジェクトがその振る舞いを変更することができる。
状態そのものをクラスとすることで、if分やswitch分の分岐を追加する必要がなくなる。


## 試しに作ったもの
車を想定した画面を作ってみました。
`パーキング`、`バック`、`ドライブ`のモードがあり、それぞれの状態でブレーキ、アクセルを押した時のリアクションが変わります。

モードのボタンを押すと、押したボタンが黄色になります。

|<img width="250" alt="Composite.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/54e048ae-7764-7cb2-118f-719fcadbb1de.png">|
|:--|

それぞれの状態で、`アクセル`→`ブレーキ`の順にボタンを押した時の状態です。

|パーキング状態|ドライブ状態|バック状態|
|---|---|---|
|<img width="180" alt="parkingState.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/774a169d-9a76-0968-b2d8-604a9ed38a5c.png">|<img width="180" alt="RunningState.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/2e0a896c-7195-d2eb-34e2-54b2237e8af2.png">|<img width="180" alt="BackState.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/dd3356f6-3297-9b2d-a545-796bee8b719a.png">|

## クラス図
`State`は全ての状態クラスの共通プロトコルで、全クラスで同じインターフェースを実装するので交換が可能になる。
ここでは`StateViewController`が俗に言う`Context`と呼ばれる、多数の内部状態を持つクラスになる。

|<img width="600" alt="State.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/654b491a-f5bb-29fe-1e5c-150af144f448.png">|
|:--|

## 実装
```swift:State
protocol State {
    /// アクセル
    func run()
    /// ブレーキ
    func stop()
}

// Back, Runningの場合も同様
class ParkingState: State {
    func run() {
        print("動きません")
    }

    func stop() {
        print("既に停止しています")
    }
}
```

```swift:StateViewController.swift
class StateViewController: UIViewController {
    /// 停車状態
    private let parkingState = ParkingState()
    /// 戻る状態
    private let backState = BackState()
    /// 走行状態
    private let runningState = RunningState()

    /// 状態フラグ（初期値は停車状態）
    private var state: State = ParkingState()

    override func viewDidLoad() {
        super.viewDidLoad()

        setup()
    }

    // 各モードの切り替え

    @IBAction func didTapParkingButton(_ sender: Any) {
        setState(with: parkingState)

        // ボタンの色状態を変える処理は省略
    }

    @IBAction func didTapBackButton(_ sender: Any) {
        setState(with: backState)
    }
    
    @IBAction func didTapDriveButton(_ sender: Any) {
        setState(with: runningState)
    }

    // 各アクション

    @IBAction func didTapBreakButton(_ sender: Any) {
        state.stop()
    }

    @IBAction func didTapRunButton(_ sender: Any) {
        state.run()
    }

    /// 準備
    func setup() {
        parkingButton.backgroundColor = .yellow
        setState(with: parkingState)
    }

    /// 状態をセット
    /// - Parameter state: State
    func setState(with state: State) {
        self.state = state
    }
}
```
# Compoundパターン
## 概要
デザインパターンを複数組み合わせたパターン。

書籍以外に参考にできるものはないかを検索してもなかなか出てこなかった。

どうやら**デザインパターンを組み合わせてアーキテクチャにしたもの**といった表現もあり、**MVC**も一種のCompoundパターンのようです。

## 作ったもの
オリジナルのものを考えるのが大変だったので、参考書籍の部分からSwiftでも実装できそうな部分をなるべく抽出して作成しました。
DJの操作画面みたいなもので、BPMの調整ができます。

|<img width="300" alt="CompoundSampleApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/1b3c8ea7-9934-d566-250c-75d4f4d57b70.png">|
|:--|


## クラス図
必要そうな部分だけ抜き取りました。

`View`：画面の構成をする。画面の各パーツの状態を監視し、状態によって処理を変えたりする。
`Controller`：Viewでのユーザの操作/入力を受け取り、Modelにとってどのような意味を持つかを解釈してModelに渡す。
`Model`：画面の状態やデータを取り扱う。Controllerから受け取った状態によって値を更新し、更新後はViewのオブザーバーに通知を送る。

**監視**や**通知**といっているので、`Observerパターン`を利用していることはわかりやすいかと思います。

また、今回の例ではあまり恩恵を得られていないかもしれませんが、`DJView`が`ControllerInterface`を参照していますが、これによって**BPMControllerではない別のController**を使いたいとなった時に交換が容易になります。
これは俗に言う`Strategyパターン`を用いています。

|<img width="820" alt="Compound.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/07db33ff-2994-430b-20e5-2c7712a9a44c.png">|
|:--|

## 実装
全部載せようとすると長くなりそうなのでリポジトリから[コード](https://github.com/ta9yamakawa/DesignPatterns/tree/main/DesignPatterns/patterns3/Compound)をご覧いただければと思います。

# おさらい
| パターン | 特徴 |
|:-----------|:-----------|
| Iterator | 集約したオブジェクトにアクセスして、読み込みや操作可能にする |
| Composite | オブジェクトをツリー構造にして扱うことで、呼び出す側で親/子を気にしないで呼び出せる |
| State | オブジェクトの状態をクラスにすることで、オブジェクトが振る舞いを変更可能にする |
| Compound | デザインパターンを組み合わせたパターン |

今回も4つのデザインパターンについて学びました。
今回のデザインパターンも[GitHubのリポジトリ](https://github.com/ta9yamakawa/DesignPatterns)で公開していますので、具体的な実装をみたい方がいらっしゃったらご覧ください。
今回のパターンは**Patterns3**のディレクトリ内に含まれています。

ここまで長かった...
デザインパターンって多いし、中にはこれなんか似てね？みたいなのもあるかと思います。

引き続き、本記事でもご指摘やアドバイス等があればぜひコメントをいただきたく思います。
いただいたコメントを踏まえて、学びをより深いものにして行けたらと思っております✨

一旦デザインパターンを学ぶシリーズはここまでにしようと思います。
参考書籍にはおまけで他のパターンもありましたが、そちらはぜひご自分の目でご確認いただければと思います。

これまで読んでくださった方も、これだけ読んだよという方も、この記事にたどり着いてくださりありがとうございました。

## 参照

**共通**
[Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本](https://www.amazon.co.jp/Head-First%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-%E2%80%95%E9%A0%AD%E3%81%A8%E3%81%8B%E3%82%89%E3%81%A0%E3%81%A7%E8%A6%9A%E3%81%88%E3%82%8B%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%AE%E5%9F%BA%E6%9C%AC-Eric-Freeman/dp/4873112494)

**Iteratorパターン**
[デザインパターン「Iterator」 - Qiita](https://qiita.com/shoheiyokoyama/items/3f42d0057d9d5a861039)

**Compositeパターン**
[Swiftで学ぶデザインパターン13 (Compositeパターン) - しめ鯖日記](https://llcc.hatenablog.com/entry/2015/07/18/131528)

**Stateパターン**
[State – 野生のプログラマZ](http://harumi.sakura.ne.jp/wordpress/2018/12/22/state/)

**Compoundパターン**

1. [【デザインパターン】コンパウンドパターン【事前学習編1】](https://doriven.hatenablog.com/entry/2014/10/11/174348)
1. [【Swift】MVCについて分かりやすいサンプルが無かったのでSwiftでMVCモデルで簡易アプリ書いてみた【MVCパターン】](https://note.com/iga34engineer/n/n37642378d20b)