repository pattern in swift
TRANSCRIPT
![Page 1: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/1.jpg)
Naoto Kaneko
Repository pattern in Swift
![Page 2: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/2.jpg)
![Page 3: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/3.jpg)
リポジトリパターン•リポジトリとは、データの取得、保存、削除のためのインターフェイス
• リポジトリを使ってデータにアクセスする。
• メモリ、Realm、APIといったバックエンドを知る必要がなくなる。
![Page 4: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/4.jpg)
ViewController
RecipeRepository
WebAPIRecipeRepository RealmRecipeRepository
query model
params JSON NSPredicate RealmObject
![Page 5: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/5.jpg)
in Swiftprotocol RecipeRepository { func find(id: UInt) -> Recipe? func findAll(query: Query, sort: Sort) -> [Recipe] func save(recipes: [Recipe]) -> Recipe? func delete(recipes: [Recipe]) -> Recipe?}
![Page 6: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/6.jpg)
in Swiftclass MemoryRecipeRepository: RecipeRepository { let recipes = [ Recipe(id: 1, name: “…”), Recipe(id: 2, name: “…”), Recipe(id: 3, name: “…”), ]
func find(id: UInt) -> Recipe? { recipes.filter { $0.id == id }.first }}
![Page 7: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/7.jpg)
問題点•データへのアクセスはだいたい非同期
• クエリやソートはどうやって指定するのか
• RecipeRepository, ChefRepository, UserRepository…と似たようなコードをコピペすることになりそう
![Page 8: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/8.jpg)
リポジトリで非同期処理をあつかう
![Page 9: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/9.jpg)
Promiseprotocol RecipeRepository { func find(id: UInt) -> Task<Void, Recipe, ErrorType> func findAll(query: Query, sort: Sort) -> Task<Void, [Recipe], ErrorType> func save(recipes: [Recipe]) -> Task<Void, Recipe, ErrorType> func delete(recipes: [Recipe]) -> Task<Void, Recipe, ErrorType>}
![Page 10: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/10.jpg)
ViewController
RecipeRepository
WebAPIRecipeRepository RealmRecipeRepository
query model
params JSON NSPredicate RealmObject
![Page 11: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/11.jpg)
ViewController
RecipeRepository
WebAPIRecipeRepository RealmRecipeRepository
Task<Void, Model, Error>
params JSON NSPredicate RealmObject
query
![Page 12: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/12.jpg)
汎用的なクエリを定義する
![Page 13: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/13.jpg)
naoty/AnyQuerylet query = AnyQuery.Equal(key: “name”, value: “naoty”)query.predicate //=> NSPredicate(format: "name == ‘naoty’")query.dictionary //=> ["name": “naoty”]
let sort = AnySort.Ascending(key: “id”)sort.sortDescriptors //=> [NSSortDescriptor(key: "id", ascending: true)]sort.dictionary //=> ["sort": ["id"]]
![Page 14: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/14.jpg)
naoty/AnyQueryprotocol RecipeRepository { func find(id: UInt) -> Task<Void, Recipe, ErrorType> func findAll(query: AnyQuery, sort: AnySort) -> Task<Void, [Recipe], ErrorType> func save(recipes: [Recipe]) -> Task<Void, Recipe, ErrorType> func delete(recipes: [Recipe]) -> Task<Void, Recipe, ErrorType>}
![Page 15: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/15.jpg)
ViewController
RecipeRepository
WebAPIRecipeRepository RealmRecipeRepository
Task<Void, Model, Error>
params JSON NSPredicate RealmObject
query
![Page 16: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/16.jpg)
ViewController
RecipeRepository
WebAPIRecipeRepository RealmRecipeRepository
Task<Void, Model, Error>
[String: AnyObject] JSON NSPredicate RealmObject
AnyQuery
![Page 17: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/17.jpg)
汎用的なリポジトリ型 を定義する
![Page 18: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/18.jpg)
これはできないprotocol Repository { associatedtype Domain
func find(id: Uint) -> Task<Void, Domain, ErrorType>}
let repository: Repository = MemoryRecipeRepository()
![Page 19: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/19.jpg)
型消去struct AnyRepository<DomainType>: Repository { let _find: (id: UInt) -> Task<Void, DomainType, ErrorType>
init<T: Repository where T.Domain == DomainType>(_ repository: T) { _find = repository.find }
func find(id: UInt) -> Task<Void, DomainType, ErrorType> { return _find(id) }}
let repository = AnyRepository(MemoryRecipeRepository())// repository: AnyRepository<Recipe>
![Page 20: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/20.jpg)
ViewController
RecipeRepository
WebAPIRecipeRepository RealmRecipeRepository
Task<Void, Model, Error>
[String: AnyObject] JSON NSPredicate RealmObject
AnyQuery
![Page 21: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/21.jpg)
ViewController
AnyRepository<Recipe>
WebAPIRecipeRepository RealmRecipeRepository
Task<Void, Model, Error>
[String: AnyObject] JSON NSPredicate RealmObject
AnyQuery
![Page 22: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/22.jpg)
実装例• https://github.com/naoty/Playground/tree/master/Repository
![Page 23: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/23.jpg)
応用例: キャッシュ
![Page 24: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/24.jpg)
キャッシュ•リポジトリから取得した結果をキャッシュしたい。
• キャッシュになければ別のリポジトリから取得して、キャッシュに保存した上で返す。
• キャッシュにあれば返す。
• 例: ログインユーザーの取得など
![Page 25: Repository pattern in swift](https://reader033.vdocuments.pub/reader033/viewer/2022051710/5aab839c7f8b9a52318b4b45/html5/thumbnails/25.jpg)
ありがとうございました