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)