最小単位でFluxアーキテクチャを試す

## 概要
Fluxアーキテクチャを最小単位で実装してみます。
今回は`RxSwift`を用いてFluxのサンプルを実装します。

## 環境
`Xcode 13.1`
以下の内容はXcodeのPlayground環境を使ってます。
環境を作るときは以下のリンクを参考にしました。

https://qiita.com/jollyjoester/items/5769f06e48879118a632

## Fluxアーキテクチャの登場人物
以下にFluxアーキテクチャの登場人物を簡単に紹介します。

### View
画面表示とユーザーイベントをハンドリングします。

### Store
アプリケーションの状態を管理します。

### Action
Storeを変更できる唯一の存在です。

### Dispatcher
Actionは必ずDispatcherを通してStoreへ渡されます。
具体的にはDispatcherにdispatchというメソッドを実装し、
Actionを渡せるようにします。

## Fluxアーキテクチャとは？
2014年にFacebookが発表したアーキテクチャです。
特徴はデータの流れが単一方向であることです。
データは以下のような流れをたどります。
1. Viewでイベントが発生する
2. イベントをトリガーにActionCreatorがActionを作成する
3. Dispatcherを通してActionがStoreへ渡される
4. 渡されたActionをStoreが解釈して自身を更新する
5. Storeを監視しているViewが更新される

## サンプルを作成する
実際にサンプルを作ってみます。

### `Store`を実装する
アプリケーションの状態は一つなのでシングルトンで実装します。

```swift:FluxPlayground
import RxSwift
import RxCocoa

final class Store {
    static let shared: Store = .init()
    private let _number = BehaviorRelay<Int>(value: 0)
    var number: Int {
        return _number.value
    }
    var numberObservable: Observable<Int> {
        return _number.asObservable()
    }
    
    private init() {}
}
```

### `Action`を実装する
StoreはActionを解析して自身を更新します。
アプリケーションの規模が大きくになるにつれて種類が増えるため、
`enum`で表現します。

```swift:FluxPlayground
enum Action {
    case updateState(Int)
}
```

### `Dispatcher`を実装する
二つの関数を実装します。
1. `Store`に`Action`を登録するための関数 `register(callback:)`
2. `Action`を実行するための関数 `dispatch()`

```swift:FluxPlayground
final class Dispatcher {
    static let shared: Dispatcher = .init()
    private let _action = PublishRelay<Action>()
    
    private init() {}
    
    func register(callback: @escaping (Action) -> ()) -> Disposable {
        return _action.subscribe(onNext: callback)
    }
    
    func dispatch(_ action: Action) {
        _action.accept(action)
    }
}
```

### `Store`に`Action`を登録する
`Action`に応じて`Store`が更新されるように初期化処理を記述します。

```swift:FluxPlayground
final class Store {
    static let shared: Store = .init()
    private let _number = BehaviorRelay<Int>(value: 0)
    var number: Int {
        return _number.value
    }
    var numberObservable: Observable<Int> {
        return _number.asObservable()
    }
    
    // 以下追加
    private init(dispatcher: Dispatcher = .shared) {
        dispatcher.register { action in
            switch action {
            case .updateState(let int):
                self._number.accept(int)
            }
        }
    }
}
```
全体のコードです。

```swift:FluxPlayground
import RxSwift
import RxCocoa

enum Action {
    case updateState(Int)
}

final class Store {
    static let shared: Store = .init()
    private let _number = BehaviorRelay<Int>(value: 0)
    var number: Int {
        return _number.value
    }
    
    private init(dispatcher: Dispatcher = .shared) {
        dispatcher.register { action in
            switch action {
            case .updateState(let int):
                self._number.accept(int)
            }
        }
    }
}

final class Dispatcher {
    static let shared: Dispatcher = .init()
    private let _action = PublishRelay<Action>()
    
    private init() {}
    
    func register(callback: @escaping (Action) -> ()) -> Disposable {
        return _action.subscribe(onNext: callback)
    }
    
    func dispatch(_ action: Action) {
        _action.accept(action)
    }
}

print("Initial State: \(Store.shared.number)") // => Initial State: 0
Dispatcher.shared.dispatch(.updateState(2))
print("Next State: \(Store.shared.number)") // => Next State: 2
```

`Store`の初期状態が0です。
その後、`Action`をディスパッチすることで状態が更新されることが確認できました。

## 参考リンク

https://peaks.cc/books/iOS_architecture