1. 概要(Overview)
Replace Data Value with Object は、単純なデータ(数値や文字列など)が、
- 追加のロジックを必要とする
- 複数箇所で一貫した扱いが必要になる
といった状況に成長したとき、そのデータを 専用のオブジェクトに置き換える リファクタリングです。
目的は以下の通りです:
- データに関連する振る舞いを一か所にまとめる
- データとロジックを密接に関連づけることで、保守性を高める
- 再利用性と表現力を向上させる
2. 適用シーン(When to Use)
- 単純なフィールドが、検証・計算・フォーマット などのロジックを必要としている
- データ値がコードのあちこちに存在し、不整合のリスク がある
- その値を「一つの概念」としてモデル化した方が自然
- 「ただの数値/文字列」では意味が不明確
よくある匂い:
- Primitive Obsession(基本型執着)
- Duplicate Code(重複コード)
3. 手順(Mechanics / Steps)
- データ値を保持しているフィールドを特定
- 新しいクラスを作成し、そのデータ値をフィールドとして持たせる
- データに関連するロジック(検証、フォーマットなど)を新クラスに移す
- 元のクラスでフィールドを新クラス型に置き換える
- クライアントコードを修正
4. Kotlin 例(Before → After)
Before:ただのデータ値
class Order(val id: Int, val customer: String)
-
customerは単なる文字列 - しかし将来「名前のフォーマット」「メールとの関連付け」など、ロジックが増える可能性がある
After①:オブジェクトに置き換え
class Customer(val name: String) {
fun isValid(): Boolean = name.isNotBlank()
}
class Order(val id: Int, val customer: Customer)
→ customer を Customer クラス に置き換え。
→ 今後ロジック(検証や属性追加)が必要になっても自然に拡張できる。
After②:さらに責務を拡張
class Customer(val name: String, val email: String) {
fun isValidEmail(): Boolean = email.contains("@")
fun displayName(): String = name.uppercase()
}
class Order(val id: Int, val customer: Customer)
→ 単なるデータだったものが 意味を持つオブジェクト に進化。
5. 効果(Benefits)
- データと振る舞いをまとめることで 高凝集化
- 変更が一か所に集まり、保守性・拡張性が向上
- 意図が明確になり、自己文書化コード に近づく
- Primitive Obsession を解消できる
6. 注意点(Pitfalls)
- 単純すぎるデータに適用すると クラスが増えすぎる
- 過剰に適用すると 設計が複雑化 するリスクがある
- 「意味ある概念」としてモデル化できる場合にだけ適用すべき
まとめ
- Replace Data Value with Object は「単純なデータを、意味を持つオブジェクトに進化させる」リファクタリング
- 判断基準:このデータは独自のロジックや一貫性を必要としているか?
- 基本思想:ドメインの概念を明示化して、モデルをより表現力豊かにする