Swift では Protocol を積極的に使おう

  • 203
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

これはなに

Swift ではクラスベースの開発よりもプロトコルベースの開発にしていきましょう。という提案です。
もうサブクラスとはお別れです。

環境

  • Swift 2.2

Protocol とは

Objective-C では @interface と書いていたものといえばイメージがしやすいと思いますが、 Swift ではこれの機能がかなり拡張されています。
特に Swift 2.0 以降では Protocol Extension の機能が追加され、 Protocol がデフォルト実装をもてるようになったのでさらに便利になりました。

使用例

とりあえず、犬猫をわんわんニャーニャー鳴かせてみましょう。

swift
protocol Animal {
    var name: String { get }
    var age: Int { set get }
    func bark() -> String
}

動物のインターフェースをこのように切ります。 name は読み取り専用、age は読み書きできます。

swift
struct Cat: Animal {
    let name = "Tama"
    var age = 2
    func bark() -> String {
        return "にゃ〜ん"
    }
}

let cat = Cat()
cat.name          // "Tama"
cat.age           // 2
cat.bark()        // "にゃ〜ん"

猫を鳴かせるにはこうです。Protocol で宣言した変数、関数を実装すればよいですね。

ただ毎回鳴き声を実装するのが大変な場合があります。基本的に動物が「ぼえ〜」と鳴くならばデフォルトで「ぼえ〜」と鳴かせておけばいいですね。

swift
extension Animal {
    func bark() -> String {
        return "ぼえ〜"
    }
}

Protocol を拡張しました。これで bark() のデフォルト実装がもてました。

swift
struct Dog: Animal {
   let name = "Pochi"
   var age = 3
}

let dog = Dog()
dog.name        // "Pochi"
dog.age         // 3
dog.bark()      // "ぼえ〜"

はい、実装しなくても関数を呼ぶことができました。デフォルト実装を使わない場合は Dogbark() を実装すればよいです。

なにがいいか

構造体で使える

Swift の構造体は構造体を継承できないのでプロトコルを実装することになります。
構造体は値型ゆえクラスよりも取り扱いがしやすい(と個人的に思っている)ので UI 部分はともかくロジック部分では多用していることでしょう。実際のアプリケーション開発では似たような部品を作ることが多いので、それがひとつのプロトコルにまとまっていると大変スッキリするかと思います。

実体とインターフェースを切り離せる

Protocol は最初に述べたようにインターフェースなので、他から参照するのを実体ではなく Protocol を参照するようにすれば依存性を減らすことができます。

swift
struct Owner {
   let pets: [Animal]
}

let owner = Owner(pets: [Dog(), Cat()])

この例だと初期化のところがまだ面倒ですが、Dog がいなくなったり、新しく動物が増えたりしても Owner 構造体には影響しません。

Override がない

Protocol には Override はありません。デフォルト実装を使うか、1から実装するかです。
これはバグを減らせると私は考えています。同じ関数名で異なる動きをする関数は混乱を招きます。
それに、UIView のサブクラスの override func layoutSubviews() 内で super.layoutSubviews() を何気なく呼んだために期待通りの動作にならなかった経験のある人は多いとおもいます。

宣言をしないと使えない

Protocol をもつクラス・構造体はその Protocol の実装をするのが必須になっています。Protocol の実装を明示することで動作をわかりやすくする働きがあると思います。基底クラスを作るために extension UIViewController をするよりも各クラスに Protocol を実装したほうがブラックボックス化を防げるでしょう。

まとめ

もちろんサブクラスでも同じ実装はできるのですが、Swift では Protocol を使うとよりスッキリした、読みやすいコードが書けると思いました。
また、例では Protocol の基本的な実装しか紹介しなかったので公式ドキュメントや他の記事で参考にされるとよいかと思います。

参考