【Kotlin】拡張関数・拡張プロパティについて
2025-04-30
拡張関数・拡張プロパティとは?
拡張関数・拡張プロパティは、既存のクラスに対して「新しい関数やプロパティを追加できる」Kotlin の特徴的な機能です。
そのクラスのソースコードを直接変更せずに、まるでそのクラスに元からあったかのように呼び出すことができます。
拡張関数
kotlin
// 拡張関数の定義:String型に "addHello" という関数を追加
fun String.addHello(): String {
// "Hello, 元の文字列" を返す
return "Hello, $this"
}
fun main() {
val name = "Tanaka"
// 拡張関数の呼び出し:まるでString型にメソッドがあるかのように使える
println(name.addHello()) // 出力: Hello, Tanaka
}
ポイント
- fun クラス名.関数名() で拡張関数を定義可能
- this は拡張対象(この例では String)を指定している
拡張プロパティ
kotlin
// データクラス User を定義
data class User(val name: String, val age: Int)
// 拡張プロパティ:User型に "isAdult" というプロパティを追加
val User.isAdult: Boolean
get() = age >= 20 // 20歳以上ならtrue、未満ならfalseを返す
fun main() {
val user1 = User("Yamada", 25)
val user2 = User("Suzuki", 18)
// 拡張プロパティの使用:直接プロパティのようにアクセスできる
println("${user1.name} is adult: ${user1.isAdult}") // 出力: Yamada is adult: true
println("${user2.name} is adult: ${user2.isAdult}") // 出力: Suzuki is adult: false
}
ポイント
- val クラス名.プロパティ名: 型 の形で拡張プロパティを定義
- 実体のフィールドは持てないため、getter で値を返すことが必須
ユースケース
拡張関数・拡張プロパティを使うべきケース
ケース | 説明 |
---|---|
既存クラスを変更できないとき | ライブラリや標準クラス(例: String, List)に処理を追加したい場合 → Kotlinなら String.isValidEmail() などで柔軟に対応可能 |
ドメインクラスを肥大化させたくないとき | ドメインモデルに属さない一時的・補助的な処理を切り離して記述できます |
複数箇所で使われる共通処理を集約したいとき | メソッド化して再利用性・テスト性を高められます |
表示用などのView変換処理 | User.displayName() や User.toUiModel() など、UI層での加工に便利です |
テストやユースケース単位のロジックを分離したいとき | ユースケースに限定したロジック(例:一時的なフィルタや条件)を、ドメイン外に安全に置けます |
拡張関数・拡張プロパティを使うべきでないケース
ケース | 説明 |
---|---|
クラスの本来の責務である処理 | 例:User における年齢加算など、本質的な振る舞いはクラス内に書くべきです。 → メソッドとして定義するのが自然 |
内部状態を保持する必要があるとき | 拡張プロパティは backing field(状態保持)を持てません → 続的な状態が必要な場合は使えません |
クラスの振る舞いを覆い隠すような用途 | 例えば String.toString() のような、元々存在する関数と被る定義は混乱やバグの原因になります |
過剰に使いすぎて可読性が落ちるとき | 特に同じ型に多くの拡張をすると、補完やリーダビリティが低下します → チーム内のスタイルガイドで整理すべきです |
DDDでの活用方法
ドメイン層はビジネスルールだけに専念させ、
アプリケーション層や プレゼンテーション層で必要な「変換」「表示」「ユースケース固有ロジック」は拡張で切り出すことで責務の分離が可能になる。
kotlin
// Domain層(純粋なEntity:変更なし)
data class Product(val id: String, val price: Int)
// Application層:DTO への変換を拡張関数で定義
fun Product.toDto(): ProductDto = ProductDto(id = id, price = price)
// Presentation層:画面表示用の文字列整形をさらに拡張
fun ProductDto.toViewText(): String = "商品#${id}:¥${price}"
まとめ
とても便利な機能である一方、開発者ごとに賛否がありそうなので、チーム内で競技してから利用する必要があると感じました。