【Swift】この世で一番わかりやすいデリゲートのお話

# この記事は何？
iOSアプリ開発を学び始めると、大抵の初学者はデリゲートがなかなか理解できずに苦しみます。私もその1人でした。しかし、それも今となっては昔の話。いつの間にか「そんなものなんだな」と理解したつもりになって、適当に使っていました。
ここらで一旦、「誰にでもわかるように説明できるのか」をテーマに解説してみたいと思いました。

> Swiftを基礎から学ぶには
自著、工学社より発売中の「[まるごと分かるSwiftプログラミング](https://amzn.asia/d/7YPWJwl)」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。
> また、Swiftプログラミングを基礎から動画で学びたい方には、Udemyコース「[今日からはじめるプログラミング](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwii1qTuj_2BAxV4hlYBHbj5BqEQFnoECBYQAQ&url=https%3A%2F%2Fwww.udemy.com%2Fcourse%2Fstart-programming-today%2F&usg=AOvVaw2vs4Sccq-bpfA4ZD2rCyNm&opi=89978449)」をお勧めします。

## 実行環境
Swift 5.3
Xcode 12.4
macOS 11.2

## はじめに
デリゲートを理解するためには、プロトコルを知っておく必要があります。
必要最低限のプロトコルについて、[こちら](https://qiita.com/chino_tweet/items/486744701cf64eb6fc83)で解説しています。

#ハンズオン
実際にコードを書きながら、説明していきます。
まずは、次のようなプロトコルを定義しておきます。

````Swift
protocol LanguageDelegate {
    func hello()
}
````

この`LanguageDelegate`プロトコルは、`hello()`メソッドの実装を要件としています。
つまり、このプロトコルへの適合は、「その言語を知っているなら、挨拶ができる」と保証することを意味します。

実際に、そのようなクラスを定義してみましょう。

````Swift:
class Japanese: LanguageDelegate {
    func hello() {
        print("やあ")
    }
}
let japanese = Japanese()
````

これは、日本語をモデル化するクラスです。
`hello()`メソッドを実装しているので、`LanguageDelegate`プロトコルに適合しています。
インスタンスも作成しておきます。

英語やイタリア語のクラスも、同じように定義してみましょう。

````Swift:
class English: LanguageDelegate {
    func hello() {
        print("Hello")
    }
}
let english = English()

class Italiano: LanguageDelegate {
    func hello() {
        print("Ciao")
    }
}
let italiano = Italiano()
````

ここまではプロトコルのお話なので、難しいことはないですね。
ここからがデリゲートの出番です。
それでは、「挨拶できる人間」をクラスとして定義してみましょう。

````Swift
class Person {
    func greeting() {
        // say something...
    }
}
let someOne = Person()
````

このクラスをインスタンス化した「誰かさん`someOne`」は、何語でどんな挨拶ができるでしょうか？
その方法をこの「誰かさん」が決めるのではなく、他のクラスに「おまかせ」するのがデリゲートです。
本来、デリゲート（Delegate）とは「移譲する」という意味です。

`Person`クラスの定義に、以下の2行を追記しましょう。

````Swift:
class Person {
    var delegate: LanguageDelegate?    // おまかせ先
    func greeting() {
        delegate?.hello() // おまかせ先の言語で挨拶
    }
}
let someOne = Person()
````

ここでは、変数`delegate`の型が`: LanguageDelegate`と明示されていることに注目します。最初に定義したプロトコルを型として利用していますね。つまり、この変数プロパティには「`LanguageDelegate`に適合した型」ならなんでも割り当てることができます。

日本語を示すインスタンスを設定してみましょう。

````Swift:
someOne.delegate = japanese
someOne.greeting()    // prints "やぁ"
````

「誰かさん」は日本語が喋れるようになったので、挨拶も「やぁ」と出力されます。
英語やイタリア語を喋れるようにするには、インスタンスの`delegate`プロパティにそれぞれの言語インスタンスを設定します。

````Swift:
someOne.delegate = english
someOne.greeting()    // prints "Hello"

someOne.delegate = italiano
someOne.greeting()    // prints "Ciao"
````

これがいわゆる「デリゲート・パターン」です。
`someOne.greeting()`というコードが3回、実行されていますが出力結果はどれも異なる挨拶です。
デリゲート先に実装を移譲しているからですね。

##何が嬉しいのか
デリゲート・パターンの利点は、ここからです。
あなたが王様になって、新しい国を作ったとしましょう。もちろん、使用言語も独自のものです。
以下のように、クラスとして定義しましょう。

````Swift
class MyKingdom: LanguageDelegate {
    func hello() {
        print("🤟")
    }
}
let myKingdom = MyKingdom()
````

とてもファンキーな挨拶ですね。飛沫も飛ばないので安全です。
「誰かさん」も、この国の言語を喋れるようにデリゲート先を設定しましょう。

````Swift:
someOne.delegate = myKingdom
someOne.greeting()    // prints "🤟"
````

`Person`クラスの実装に触れることなく、「誰かさん」の挙動を変更できました。
デリゲート・パターンのメリットは、「実装方法を定義するときではなく、後で決定できる」ことです。

さらに、「別の誰か」を作成しましょう。
この「別の誰か」は、イタリア語を喋ります。

````Swift:
let anoterOne = Person()
anotherOne.delegate = italiano
anotherOne.greeting()    // prints "Ciao"
````

`someOne`と`anotherOne`は、同じ`Person`クラスのインスタンスなのに、`greeting()`メソッドの挙動が異なります。
それぞれのインスタンスは、デリゲート先が別の言語クラスになっているからですね。
これも、デリゲート・パターンの利点です。

## 説明は以上です

いかがだったでしょうか？
長くなってしまいましたが、iOSやビューコントローラの概念と切り離して、できるだけシンプルにデリゲート・パターンを説明してきました。
このように説明することで、自分自身の理解も整理することができました。
感想なども、ぜひコメントしていただけると嬉しいです。