Protocolってなぁになぁに?
はじめに
記事を書いた経緯
現在参加させていただいているCA-TechAccelで学んだことを記事にしてアウトプットしている最中でTestableなコードを意識する上でProtocolを使用する流れになったので調べたことや気づいたことをまとめる備忘録として書いていこうと思います。
Protocolとは
Swiftのプロトコルは、型のインターフェースを定義するものです。インターフェースを定義し、抽象化することによって、複数の型で共通の機能を実装することができます。プロトコルはクラス、構造体、列挙型などで使われ、プロトコルのインターフェースを満たす型は、プロトコルに準拠していると言われています。
メンターさんからこんなことを聞きました。
コードにしてみるとこんな感じ
import Foundation
protocol UserDefaultsProtocol {
func fetchTasks() -> [ToDo]?
func saveTasks(taskList: [ToDo])
}
思っているより単純。
やってることとしてはstructを作っているみたい。
その後に実際にこのprotocolに準拠したserviceを作成してみる。
import Foundation
final class UserDefaultsService: UserDefaultsProtocol {
static let storeKey = "TaskListKey"
public func fetchTasks() -> [ToDo]? {
if let data = UserDefaults.standard.data(forKey: UserDefaultsService.storeKey) {
do {
let tasks = try JSONDecoder().decode([ToDo].self, from: data)
return tasks
} catch {
print(error)
return nil
}
} else {
return []
}
}
public func saveTasks(taskList: [ToDo]) {
do {
let data = try JSONEncoder().encode(taskList)
UserDefaults.standard.set(data, forKey: UserDefaultsService.storeKey)
} catch {
print(error as Any)
}
}
}
上のコードにおいて、UserDefaultsServiceはUserDefaultsProtocolに準拠しているため
import Foundation
final class UserDefaultsService: UserDefaultsProtocol {
//storeKeyの設定
public func fetchTasks() -> [ToDo]? {
// 配列のFetch
} catch {
// エラーハンドリング
}
} else {
return []
}
}
public func saveTasks(taskList: [ToDo]) {
// 配列の保存
} catch {
// エラーハンドリング
}
}
}
この2つのメソッドが作成されていなければブチギレられるので注意!
このように明示的にどのようなメソッドが作られるのか、あらかじめ指定しておくことでViewModelなどで、いちいちインスタンスを作らなくても良くなる
簡単なイメージ
実際にインスタンスを作成するのはViewで作成することになるのだが、それまではprotocol(仕様書)を用いてコードをカキカキします。
それをイメージする前に一旦インスタンスについておさらいしましょう。
インスタンスはよく車の製造に喩えられますよね
例えば、色に赤色染料を入れるのか、それとも青色染料を入れるのか。
車を作る際のの型の中に流し込む染料がインスタンスと言われます。
で、その設計書がprotocolな訳です。
例えば、車を作る過程で実際にコンベアの上で実物(インスタンス)を作成するまでの間、設計であったり、さまざまなMTGの場で使われるのはインスタンスではなく、設計書ですよね?
毎回毎回インスタンスを作らないようにして、設計書に沿って話を進めていく。
そんなイメージを持つと少し理解しやすくなるのかな?と思います!
参考資料(再掲)
Discussion