考察　GoFデザインパターンをRx+MVVM+DDDクリーンアーキテクチャで利用できるか


# 概要

実装やデータの流れが統一できるクリーンアーキテクチャとRx+MVVMに魅了されて日々研究をしています。

30半ばの古参者でデザパタ大好き人間だったがデザパタの使い所がなかなかないので
無理やり、タイトルにもある通り「デザインパターンをRx+MVVM+DDDクリーンアーキテクチャで利用できるか」を検討してみたいと思います。

逐次更新していきます。

rxSwift/rxCocoaを前提に考察しますが、読み替えればすべての言語で対応可能になるように考察します。

# 生成に関するパターン
# Singleton

[wikipedia Singletonパターン](https://ja.wikipedia.org/wiki/Singleton_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

> Singleton パターンとは、そのクラスのインスタンスが1つしか生成されないことを保証するデザインパターンのことである。ロケールやルック・アンド・フィールなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される[1]。

## 実装

CoreLocationを利用し、位置情報を表示する
CoreLocationの処理を行うRxLocationをSingletonにしている

```ViewController.swift
import CoreLocation
import RxCocoa
import RxSwift
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        vm.latitude.asDriver().drive(latitude.rx.text).disposed(by: vm.disposeBag)
        vm.longitude.asDriver().drive(longitude.rx.text).disposed(by: vm.disposeBag)
        
        startButton.rx.tap.asDriver()
            .drive(vm.startUpdateLocationCommand)
            .disposed(by: vm.disposeBag)
    }
    
    let vm = LocationViewModel()
    
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var latitude: UILabel!
    @IBOutlet weak var longitude: UILabel!
}

class LocationViewModel {
    let usecase = LocationUsecase()
    let location = Variable<CLLocation?>(nil)
    let latitude: Driver<String>!
    let longitude: Driver<String>!
    let disposeBag = DisposeBag()
    
    init() {
        usecase.getObservable().bind(to: location).disposed(by: disposeBag)
        latitude = location.asDriver().map { $0?.coordinate.latitude.description ?? "" }
        longitude = location.asDriver().map { $0?.coordinate.longitude.description ?? "" }
        startUpdateLocationCommand.asObserver().bind(onNext: usecase.startUpdatingLocation).disposed(by: disposeBag)
    }
    
    let startUpdateLocationCommand = PublishSubject<Void>()
}

class LocationUsecase {
    private var repository = LocationRepository()
    func getObservable() -> Observable<CLLocation> {
        return repository.getObservalbe()
    }
    
    func startUpdatingLocation() {
        repository.startUpdatingLocation()
    }
}

class LocationRepository {
    private let location: RxLocation = RxLocation.shared
    func getObservalbe() -> Observable<CLLocation> {
        return location.Observable
    }
    
    func startUpdatingLocation() {
        location.startUpdatingLocation()
    }
}

class RxLocation: NSObject {
    static let shared = RxLocation()
    let locationManager = CLLocationManager()
    private override init() {
        super.init()
        auth()
    }
    
    func auth() {
        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.distanceFilter = 10
            locationManager.requestLocation()
        }
    }
    
    func requestLocation() {
        locationManager.requestLocation()
    }
    
    func startUpdatingLocation() {
        locationManager.startUpdatingLocation()
    }
    
    func stopUpdatingLocation() {
        locationManager.stopUpdatingLocation()
    }
    
    private let observer = PublishSubject<CLLocation>()
    var Observable: Observable<CLLocation> {
        return observer
    }
}

extension RxLocation: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            observer.onNext(location)
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
            break
        case .restricted, .denied:
            
            break
        case .authorizedAlways, .authorizedWhenInUse:
            break
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error.localizedDescription)
    }
}

```


## 考察

位置情報をSingletonでObservableで公開することで常に同じObservableをsubscribeできる。

※コード上はsubscribeを使わずにbindとdriveでObserverを追加している

# Abstract Factory

[wikipedia Abstract Factory パターン](https://ja.wikipedia.org/wiki/Abstract_Factory_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

> 関連するインスタンス群を生成するための API を集約することによって、複数のモジュール群の再利用を効率化することを目的とする。日本語では「抽象的な工場」と翻訳される事が多い。

## 考察

よく使われるインスタンスの生成を３パターン用意しました。

1. Factoryは具象クラス ProductはProtocol
2. Factoryは具象クラス ProductはProtocol
3. Factoryなし ProductはProtocol

```Factory1.swift
let factory: Factory = Factory()
let product = factory.create(someKind)
product.doSomething()
```



```Factory2.swift
let product:Product = Factory.create(someKind)
product.doSomething()
```

```Factory3.swift
let product:Product = Product.create(someKind)
product.doSomething()
```
どのパターンでもcreateの中身はsomeKindを判定し、適切なProductを返します。


単体テストのためにProductをMockにしたい、という場合
FactoryをMockに置き換えないといけない。
2, 3 は　staticなcreateメソッドのためモックに置き換えるのは難しい。

1のFactoryをMockに置き換えてcreateメソッドでMockProductを返すようにする。

## Usecaseのインスタンス生成をAbstractFactoryに任せてみる

```ViewModel.swift
class ViewModel {
    let some1Usecase: Some1Usecase
    let some2Usecase: Some2Usecase
    init(usecaseFactory: UsecaseFactory = UsecaseFactoryImpl()) {
        self.some1Usecase = usecaseFactory.createSome1Usecase()
        self.some2Usecase = usecaseFactory.createSome2Usecase()
    }
}
protocol Some1Usecase {}
class Some1UsecaseImpl: Some1Usecase {}

protocol Some2Usecase {}
class Some2UsecaseImpl: Some2Usecase{}

protocol UsecaseFactory {
    func createSome1Usecase() -> Some1Usecase
    func createSome2Usecase() -> Some2Usecase
}
class UsecaseFactoryImpl: UsecaseFactory {
    func createSome1Usecase() -> Some1Usecase {
        return Some1UsecaseImpl()
    }
    func createSome2Usecase() -> Some2Usecase {
        return Some2UsecaseImpl()
    }
}
```
## 直接Usecaseを渡す場合

Factoryを使わない場合(ViewModel2)とどっちが楽だろうか。

```ViewModel2.swift 
class ViewModel2 {
    let some1Usecase: Some1Usecase
    let some2Usecase: Some2Usecase
    init(some1: Some1Usecase = Some1UsecaseImpl(),
         some2:Some2Usecase = Some2UsecaseImpl()) {
        self.some1Usecase = some1
        self.some2Usecase = some2
    }
}
```

## 結論
Mockの入れ替えをする上でイニシャライザ（コンストラクタ）の引数が減るという意味では有用かもしれない。ただし必須だとは思わない。

* アプリ内のすべてのusecaseを同一のFactoryでcreateすることによって、全ViewModelのイニシャライザを統一できる、というメリットはあるかもしれない。
その場合、Mock生成も統一されたものになりテストコードの可読性が上がるかもしれない。

導入するなら導入し、すべてのクラスが同じ実装になるようにすべきではないかと思う。
一部だけ取り入れるのは後からコードを見る人間にとって混乱を招き害悪でしかない。
一部だけやってみた　のであれば「やってみた」　というコメントを残しておいて欲しい。


# Factory Method

[wikipedia Factory Method パターン](https://ja.wikipedia.org/wiki/Factory_Method_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

> Factory Method パターンは、他のクラスのコンストラクタをサブクラスで上書き可能な自分のメソッドに置き換えることで、 アプリケーションに特化したオブジェクトの生成をサブクラスに追い出し、クラスの再利用性を高めることを目的とする。

## 考察

abstract protected でcreateメソッドを定義しサブクラスで生成を切り替える。

TemplateMethodパターンの１メソッド（または複数）をFactoryにしただけと想定。

どうやってDDD+CleanArchitectureに取り入れようか。

最近、多態性＝単体テストのMockっていう思考回路になってきていて
それはそれで正しいんだけど、プロダクトコードの処理を切り替えたかったんだよ。GoFは。

でも、継承を多用すると継承がガッチガッチになるのでやっぱりMock切り替えで使ってみます。

## ViewModelにて Usecaseの生成をFactory Methodで実装してみる

```ViewMode.swift
class ViewModel{
    var usecase: Usecase!
   init() {
        usecase = createUsecase()
    }
    func createUsecase() -> Usecase {
        return UsecaseImpl()
    }
}

protocol Usecase  {}
class UsecaseImpl: Usecase {}
```

## ViewModelTestで継承でUsecaseを切り替えてみる
```ViewModelTest.swift
class ViewModelTest: ViewModel {
    override func createUsecase() -> Usecase {
        return UsecaseMock()
    }
}
class UsecaseMock: Usecase {}
```

## 結論
Testできるけど、なんか違うような？違うよね？いや、使える？！

# Builder

[wikipedia Builder パターン](https://ja.wikipedia.org/wiki/Builder_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

>  オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にする。

## 考察

Andoridのライブラリ（java/kotlin）では多用されているイメージがある。
OKHttpとか。

通信やDBアクセスや、デバイスアクセスといった外部リソースの通信ライブラリはDataレイヤーに閉じ込められる。
repositoryはどういったI/Fとして公開するかを考えれば良く、個別のライブラリの影響は受けないので、DDD+CleanArchitectureという中では利用することはないのではと思う。



# Prototype

[wikipedia Prototype パターン](https://ja.wikipedia.org/wiki/Prototype_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

>  生成されるオブジェクトの種別がプロトタイプ（典型）的なインスタンスであるときに使用され、このプロトタイプを複製して新しいオブジェクトを生成する。
> このパターンは、Abstract Factory パターンでなされるように、クライアント・アプリケーションにおいてオブジェクトの生成者をサブクラスにすることを回避する
標準的な方法（例えば'new'）で新しいオブジェクトを作ることによる固有のコストが所与のアプリケーションにとって高すぎる時にそれを回避する
ために用いられる。

## 考察

既に最近の言語では一般的になってしまったデザインパターンの一つである。
Clonableというprotocolだったりinterfaceだったり、基本的なライブラリとして提供されているため、ここでは言及する必要はないのかもしれない。

#構造に関するパターン

DDD+CleanArchitectureにおいては
Presenter/Domain/Dataの各層とそれに属する各クラスが決まっているため
構造に関するパターンを適用することはほぼないのではと考えられる。
※亜種はあるが、だいたい同じ思想である。

# Adapter

[wikipedia Adapter パターン](https://ja.wikipedia.org/wiki/Adapter_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

>  Adapter パターンを用いると、既存のクラスに対して修正を加えることなく、インタフェースを変更することができる。Adapter パターンを実現するための手法として継承を利用した手法と委譲を利用した手法が存在する。

## 考察

CleanArchitectureにおけるRepositoryの考え方がAdapterそのものだ。
ただし、委譲はするが継承はしない。

# Bridge

[wikipedia Bridge パターン](https://ja.wikipedia.org/wiki/Bridge_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

>  「橋渡し」のクラスを用意することによって、クラスを複数の方向に拡張させることを目的とする。

## 考察

特にDDD+CleanArchitectureで利用しなくてもいいかも。

以下に、復習としてBridgeをまとめます。

車でいうと 車種、カラーという二つの要素を全パターン網羅しようとすると
車種の数　かけることの　カラーの数　という組み合わせが生じてしまう。

```
例　車種: {BMW, ベンツ} 
```
```
 カラー { 赤、青、黒} 
```
```
組み合わせ {赤BMW, 青BMW, 黒BMW, 赤ベンツ、青ベンツ、黒ベンツ}  
```

さらにカーナビの種類、MT/ATなど、カスタマイズを入れると莫大な組み合わせになる。
それらをサブクラスで表現にしないで委譲を使いましょうという思想です。

```Car.swift
class Car {
    let color: Color
    let type: CarType
}
```
Bridgeしないと以下になる。こんな実装ありえない。。。

```Car.swift
protocol Car {}
class RedBMW: Car {}
class BlueBMW: Car {}
class BlackBMW: Car {}
```

ゲームだと
装備としての武器、鎧、兜、小手

アバターの髪の毛、顔パーツとか。
CM「組み合わせは１億通り！君だけのキャラを作れ！（サブクラス１億個！）」