前回に引き続き、Modelの設計についての勉強として「ドメイン駆動設計入門」を読み進めています。サンプルコードはC#で書かれていますが、iOSを勉強している人にもオススメの一冊です。
今回は9章のファクトリについての内容をベースに、Swiftのコードを使って紹介します。
イニシャライザは単純に
イニシャライザといえば、インスタンスの初期化の役目を担い、プロパティに初期値を代入する関数です。しかし、その初期化の処理が単純でなくなる場合には、ファクトリを用いて生成処理をカプセル化しましょう。
とはいえ単に「単純でないイニシャライザ」と言っても、基準が分かりづらいですよね。
「ドメイン駆動設計入門」では、その指標を以下のように示しています。
イニシャライザ内で他のオブジェクトを生成するかどうか
それでは、例を見てみましょう。
よくない例
例えば、ToDoアプリのドメインモデルとして、以下のようなModelがあるとします。
struct ToDo {
private let id: ToDoID
private(set) var title: ToDoTitle
init(id: ToDoID, title: ToDoTitle) {
self.id = id
self.title = title
}
mutating func changeTitle(_ title: ToDoTitle) {
self.title = title
}
}
ここで、ToDoを新規作成する際に、IDを渡さなくても、Model側で新しいIDを生成する仕組みを作りたいと思いました。
真っ先に頭に浮かぶのは、引数にIDが不要なイニシャライザを、別で定義することでしょう。
struct ToDo {
private let id: ToDoID
private(set) var title: ToDoTitle
+ init(title: ToDoTitle) {
+ self.id = ToDoID(UUID().uuidString)
+ self.title = title
+ }
+
init(id: ToDoID, title: ToDoTitle) {
self.id = id
self.title = title
}
mutating func changeTitle(_ title: ToDoTitle) {
self.title = title
}
}
しかし、このイニシャライザは、ToDoIDの生成という単純ではないロジックを含んでしまっています。
ファクトリを用いた例
新たなイニシャライザを作るのではなく、ファクトリでIDを生成するようにします。
struct ToDoFactory {
func create(title: ToDoTitle) -> ToDo {
let id = ToDoID(UUID().uuidString)
return ToDo(id: id, title: title)
}
}
ToDoの新規作成は、ファクトリを使って行います。
let toDoFactory = ToDoFactory()
let toDo = toDoFactory.create(title: ToDoTitle("買い物に行く"))
これによって、イニシャライザに余計なロジックを持たさずに済みます。
この例では簡単のためにUUIDでIDを生成していますが、リポジトリを呼び出してIDの生成を行うといった処理も考えられます。
メソッドをファクトリの代わりにする例
そうは言っても、わざわざFactoryを作るほど大したことはしてないんだよな... ということもあるでしょう。その場合は、このようにstaticな関数を定義して同等のことを行うのも良さそうです。
struct ToDo {
private let id: ToDoID
private(set) var title: ToDoTitle
+ static func create(title: ToDoTitle) -> ToDo {
+ let id = ToDoID(UUID().uuidString)
+ return ToDo(id: id, title: title)
+ }
+
init(id: ToDoID, title: ToDoTitle) {
self.id = id
self.title = title
}
mutating func changeTitle(_ title: ToDoTitle) {
self.title = title
}
}
let todo = ToDo.create(title: ToDoTitle("買い物に行く"))
まとめ
ファクトリは、インスタンス生成の処理の複雑さを代わりに引き受けてくれます。
イニシャライザを記述する時には、複雑な処理を書かないように注意し、必要であればファクトリを定義しましょう。
参考