why
前回まで、CA で必須である Port を省略していた。
https://dev.to/kaede_io/kotlin-ji-chu-part-5-abstract-class-to-interface-nowei-i-aok
この Kotlin 基礎の回で Port で使われる interface の使い方を理解したので入れてみる。
interface である Port を作る
package com.example.springboot
interface PersonPort {
fun getAllPersons(): Persons
}
名前と返り値の型だけ定義
Gateway をインターフェースから実装するようにする
Kotlin の文法に従って interface の中身を実装する。
クラスに実装元?の interface を書く。型みたいに。
override を関数につけて中身を書く。
クラスの引数では Driver のインスタンスを取れなくなる。
なのでクラス外部に Driver のインスタンスを作成して
そのインスタンスをクラスの内部の関数で使う。
package com.example.springboot
import org.springframework.stereotype.Component
val personsDriver = PersonsDriver()
@Component
class PersonsGateway: PersonPort {
override fun getAllPersons():Persons {
val persons = personsDriver.findAll()
return Persons(persons.map { person ->
Person(
Name(person.name),
Age(person.age)
)
})
}
}
Usecase で Port から Gateway の関数を呼び出す
class PersonsUsecase(
private val personPort: PersonPort,
) {
fun getAllPersons():Persons {
println("Usecase/")
println("getAllPersons/")
return personPort.getAllPersons()
}
fun getPersonsByAge(age: Age):Persons {
val persons = personPort.getAllPersons()
return persons.filterByLessThan(age)
}
}
Usecase では引数を Gateway のインスタンスから Port のインスタンスに変更する。
そして Port のインスタンスから呼ぶと、Gateway のインスタンスにつながる。
Rest
// 20220921234906
// http://localhost:8080/persons
{
"persons": [
{
"name": "taro",
"age": 3
},
{
"name": "hana",
"age": 5
},
{
"name": "Dominique",
"age": 11
},
{
"name": "Jackson",
"age": 11
}
]
}
Rest は何も変わらず、これでクリーンに API が分離できた。
依存性逆転、中央に依存性を持ってくることができたのだ。
まとめ
クリーンアーキテクチャで依存性逆転をしたい時は
Port にインターフェースを作って
そこから Gateway で実装を書いて
Usecase では @Component
の依存性注入で Port を入れて
Port の関数を呼ぶようにする。それで Gateway が呼ばれる。
これでようやく
Rest > (Domain) > Usecase > Port > Domain > Gateway > Driver
というクリーンアーキテクチャの 6 層の分離ができた。
Top comments (0)