protocolについて

備忘録

#はじめに
ふわっとしか理解していないのでQiitaに書こうと思いました。

#protocol
日本語に訳すと`規定`や`約束事`という意味合いになります。

Swiftにおいては、`プロパティやメソッドを定義`することができて
`クラスや構造体に準拠されること前提`で使われます。

```swift
protocol HogeProtocol {
    var hoge: String { get }
    func doHoge()
}
```
###・使い方
protocolは冒頭でも述べたようにクラスや構造体などに
準拠されること前提で使われます。

なので使用する場合は準拠することから始まります。

そして、protocolで定義したものは`必ず実装しなければなりません`。

```swift
class Hoge: HogeProtocol {
    // 実装しなければエラーが発生する
    // var hoge: String = ""
    
    func doHoge() {
        print("doHoge")
    }
}
```
###・複数準拠できる
クラスの場合、複数の継承はエラーが発生してしまいます。
ですが、protocolでは`複数準拠`が可能です。

```swift
protocol FugaProtocol {
    var fuga: String { get }
    func doFuga()
}

class HogeFuga: HogeProtocol, FugaProtocol {
    var hoge: String = ""
    var fuga: String = ""

    func doHoge() {
        print("doHoge")
    }

    func doFuga() {
        print("doFuga")
    }
}
```
###・protocolもprotocolを準拠できる
タイトル通り、protocol自身も`protocolを準拠できます`。

```swift
// 先ほど定義したProtocol達をまとめる
protocol HogeFugaProtocol: HogeProtocol, FugaProtocol {
    var hogeFuga: String { get }
}

class HogeFuga: HogeFugaProtocol {
    var hogeFuga: String = ""
    var hoge: String = ""
    var fuga: String = ""
    
    func doHoge() {
        print("doHoge")
    }

    func doFuga() {
        print("doFuga")
    }
}
```

###・protocol extension
基本的にprotocolはデフォルト実装が`できません`。
なので準拠したクラスなどで具体的な処理内容を記述しなければいけません。

ですが例外があり、`extention`によってデフォルト実装が`可能`になります。

```swift
// デフォルト実装を追加する
extension HogeProtocol {
    func doHoge() {
        print("doHoge")
    }
}

// デフォルト実装しているので実装しなくてもエラーが発生しない
class HogeFuga: HogeFugaProtocol {
    var hogeFuga: String = ""
    var hoge: String = ""
    var fuga: String = ""
    
//    func doHoge() {
//        print("doHoge")
//    }
    
    func doFuga() {
        print("doFuga")
    }
}

let hogeFuga = HogeFuga()
hogeFuga.doHoge() // "doHoge"
```

#protocolのメリット
protocolについてよく分かったけど
結局何がいいの？どこで使うの？？って感じですよね。

protocolのメリットを備忘録を含めて
つらつらと書いていこうと思います。

###・共通化できる
例えば、各動物の走ったり泳いだりなどの速さを出力したいとします。

####◯protocolを使わない場合
まずは大元の`Animalクラス`を作ります。

```swift
// 動物クラス
class Animal {
    var runningSpeed: Int?
    var swimmingSpeed: Int?
    
    func run() {
        guard let runnningSpeed = runnningSpeed else { return }
        print("走るスピードは\(String(describing: runnningSpeed))km/h です")
    }
    
    func swim() {
        guard let swimmingSpeed = swimmingSpeed else { return }
        print("泳ぐスピードは\(String(describing: swimmingSpeed))km/h です")
    }
}
```

そして、`Humanクラス`を作って
Animalクラスを継承します。

```swift
// 人間クラス
class Human: Animal {
    override init() {
        super.init()
        runningSpeed = 36
        swimmingSpeed = 8
    }
}
```

では他にも、色んな動物クラスを追加していきましょう。

```swift
// 鳥クラス
class Birds: Animal {

}
// 犬クラス
class Dog: Animal {
    
}
```
新たに作った`Birdsクラス`では飛ぶ速さを出力したいと思います。

ということは飛ぶ速さを出力するメソッド等を
大元の`Animalクラス`に追加しないといけませんね。

ついでに`Birdsクラス`・`Dogクラス`で速さが出力できるようにしていきましょう。

```swift
// 動物クラス
class Animal {
    var runningSpeed: Int?
    var swimmingSpeed: Int?
    var flyingSpeed: Int?
    
    func run() {
        guard let runnningSpeed = runnningSpeed else { return }
        print("走るスピードは\(String(describing: runnningSpeed))km/h です")
    }
    
    func swim() {
        guard let swimmingSpeed = swimmingSpeed else { return }
        print("泳ぐスピードは\(String(describing: swimmingSpeed))km/h です")
    }
    
    func fly() {
        guard let flyingSpeed = flyingSpeed else { return }
        print("飛ぶスピードは\(String(describing: flyingSpeed))km/h です")
    }
}
// 鳥クラス
class Birds: Animal {
    override init() {
        super.init()
        flyingSpeed = 340
    }
}
// 犬クラス
class Dog: Animal {
    override init() {
        super.init()
        runningSpeed = 50
        swimmingSpeed = 4
    }
}
```
これで出力できそうですね。

ただこれらのコードだと、いくつか欠点があります。

本来、呼び出す必要がないメソッド等が
`外部で呼び出せてしまいます`。

```swift
let human =  Human()
let birds = Birds()
let dog = Dog()

human.run() // 走るスピードは36km/h です
human.fly() // 何も出力されない

birds.fly() // 飛ぶスピードは340km/h です

dog.fly() // 何も出力されない
```

後は`Animalクラス`がどんどん`肥大化`してしまうという点です。

様々なクラスに対応させるために大元のクラスに色々、詰め込んでしまっては`膨大なコード量`になってしまって
`可読性も良くない`、あるクラスでは`必要ないプロパティやメソッド`などが大量生産されてしまいます。

####◯protocolを使った場合
では、protocolで実装していきます。

```swift
protocol RunProtocol {
    var runningSpeed: Int { get set }
    func run()
}
// 同じ処理の部分はextentionでデフォルト実装していく
extension RunProtocol {
    func run() {
        print("走るスピードは\(String(describing: runningSpeed))km/h です")
    }
}

protocol SwimProtocol {
    var swimmingSpeed: Int { get set }
    func swim()
}

extension SwimProtocol {
    func swim() {
        print("走るスピードは\(String(describing: swimmingSpeed))km/h です")
    }
}

protocol FlyProtocol {
    var flySpeed: Int { get set }
    func fly()
}

extension FlyProtocol {
    func fly() {
        print("走るスピードは\(String(describing: flySpeed))km/h です")
    }
}
```
そして、先ほどのクラス達に準拠していきます。

```swift
// 動物クラス
class Animal {

}
// 人間クラス
class Human: Animal, RunProtocol, SwimProtocol {
    var runningSpeed: Int = 36
    var swimmingSpeed: Int = 8
}
// 鳥クラス
class Birds: Animal, FlyProtocol {
    var flySpeed: Int = 340
}
// 犬クラス
class Dog: Animal, RunProtocol, SwimProtocol {
    var runningSpeed: Int = 50
    var swimmingSpeed: Int = 4
}

let human =  Human()
let birds = Birds()
let dog = Dog()

human.run() // 走るスピードは36km/h です
human.fly() // エラー

birds.fly() // 走るスピードは340km/h です

dog.fly() // エラー
```
見て分かるようにprotocolに定義されていないものは`エラー`となります。

そして、protocolでは定義したものは必ず実装しなければいけないルールなので
`どのプロパティに初期化が必要なのか`を考慮しなくてもよくなります。

これで`必要ないものが外部で呼び出されることはなくなりました`。

このように部分的に処理を共通化させる事によって
`必要な処理のみを実装できて可読性が向上`します。

###・ファイル間の依存関係を薄くできる
例えば、TableViewCellをタップした時に
そのCellに付随する値を違うVCに受け渡し、そのVCに画面遷移するとします。

####◯protocolを使わない場合
単純に実装すれば以下のようになると思います。

```swift
class SecondViewController: UIViewController {
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // 受け渡す値
        let model = models[indexPath.row]
        let firstVC = FirstViewController()
        // ここで他のVCに値を受け渡す
        firstVC.text = model.text
        // 画面遷移
        self.navigationController?.popViewController(animated: true)
    }
}
```
かなり雑ですが、こんな感じで他のVCに値を受け渡すことが出来ます。

ただこのコードだと`SecondViewController`は
`FirstViewController`が存在していないとエラーになります。

いわゆる`密結合`になっている状態です。
つまり、VC間の依存関係が`濃い`訳ですね。

####◯protocolを使った場合
ここでprotocolを使ったDelegateで依存関係を`薄く`していきます。

```swift
protocol ToPassDataDelegate: AnyObject {
    func didSelectData(model: Model)
}

class SecondViewController: UIViewController {
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let model = models[indexPath.row]
        // cellをタップした時に値を渡して、それ以降の処理は任せる
        delegate?.didSelectData(model: model)
        self.navigationController?.popViewController(animated: true)
    }
}
```
どこにも`FirstViewController`が記述されていないことが分かりますね。
もちろん、存在していなくても`エラーになることはありません`。

このように依存関係を薄くすることによって
たとえ違うVCに変更したとしても影響がなく、`改修しやすい`ものとなります。

これがいわゆる`疎結合`ですね。

先ほど出てきたUITableViewクラスも内部でprotocolを使ったDelegateを持っています。
依存関係が薄いからこそ、私たちは様々な処理ができるようになっている訳ですね。

###・構造体や列挙型に準拠できる
構造体や列挙型はクラスのように`継承`が出来ません。

ですが、protocolを使うことで
構造体や列挙型でも同じようなことができます。

```swift
protocol HogeProtocol {
  var hoge: String { get }
}

struct Fuga: HogeProtocol {
  var fuga: String
  var hoge: String
}
```

#おわりに
Swiftは唯一の「`Protocol指向`」のプログラミング言語だそうです。

何か間違っている部分や気になる部分があればコメントして下さると有り難いです。

#参考資料
[mixi-inc/iOSTraining](https://github.com/mixi-inc/iOSTraining/blob/master/Swift/pages/day4/2-3_protocol-oriented-programming.md)
[Swiftのプロトコルについて](https://qiita.com/Howasuto/items/546e615325f9feca55f7)
[iOSアプリの基本設計を考える：疎結合の概念から構造化、MVVM、RxSwiftまで](https://qiita.com/BlueEventHorizon/items/a712e6fa9fcdc1bdd4b5)
[Swiftのプロトコルとは？役割・使いどころ・存在意義やメリット。](https://fuuno.net/swift/protocol/protocol.html)