🏃

Swiftで部品の振る舞いを定義をする際に、Protocolを利用するべきかClassを利用するべきか

2021/12/01に公開

1. はじめに

SwiftにはProtocolという機能があります。
この機能はJavaのInterfaceに似た機能で、ある部品の振る舞いを下記のように定義できます。

protocol Door {
  var isOpened: Bool { get }
  func open()
  func close()
}

またSwiftには他のOOP言語にもあるClassの概念も存在します。

fw Door {
  var isOpened = false
  
  func open() {
    isOpened = true
  }
  
  func close() {
    isOpened = false
  }
}

大きく分けて2つの概念があるわけですが、プログラムを書くときに振る舞いをProtocolを利用して定義するべきか、Classを用いて定義するべきか迷ってしまうケースが多々有りました。

書いておかないと忘れちゃうので、メモがてら共有します。

2. Classを用いたほうが良い場合

その部品の振る舞い・役割を抽象化する必要がないのならばクラスによる継承の仕組みで部品を作っていくのが良いと考えています。

たとえば、商品の購入をするための A画面とB画面に存在する BuyButton という部品を定義する場合、「A画面にあるBuyButtonの振る舞いとB画面にあるBuyButtonの振る舞いが一致しない」ということは原則ないと考えられます。

振る舞いを変更する必要がないのであれば、実装と振る舞いが1:1で対応するクラスのほうが使い勝手が良いと考えています。

3. Protocolを用いたほうが良い場合

部品の振る舞い・役割を抽象化する必要がある場合はProtocolを利用したほうが良いと思います。

例えばViewModelのようなどのような情報を提供してほしいのかを抽象化したいというような場合には、Protocolを使うほうが良いと考えています。

protocol NotificationViewModel {
  var isRead: Bool { get }
  var title: String { get }
  var message: String { get }
  func markAsRead() -> Self
}

struct ImportantNotificationViewModel: NotificationViewModel {
  let isRead: Bool
  let title: String
  let message: String

  func markAsRead() -> ImportantNotificationViewModel {
      return ImportantNotificationViewModel(isRead: true, title: title, message: message)
  }
}

4. まとめ

一旦僕は以上のように使い分けをしています。
ご参考になれば幸いです。

Discussion