はじめに
一時フィールド(Temporary Field) とは、クラスに定義されているフィールドが
「特定の状況でしか使われず、普段は無効・null のまま」になっている状態を指します。
これはクラスが 本来の責務以上を抱えているサイン であり、読み手を混乱させる悪臭です。
13.1 特徴
- フィールドが常に使われるわけではなく、一部のメソッドでしか利用されない
-
nullチェックやisInitializedチェックがあちこちに散乱する - コンストラクタで無理に初期化されているが、実際は不要なケースが多い
- クラスが「複数の文脈」を抱え込みすぎている
13.2 解決手法
-
クラス抽出(Extract Class)
→ 一時フィールドとそれを使うメソッドを別クラスに移動 -
メソッドオブジェクト化(Introduce Method Object)
→ 複雑な処理専用のクラスを作り、一時フィールドをそこで完結させる -
ローカル変数への置換
→ メソッド内で完結できる場合はフィールドにせずローカルに閉じ込める
13.3 Kotlin 例
Before:一時フィールドがあるクラス
class ReportGenerator {
private var tempData: String? = null // 普段は null
private var tempFormat: String? = null
fun generateSummary(data: String): String {
this.tempData = data
this.tempFormat = "SUMMARY"
return process()
}
fun generateDetail(data: String): String {
this.tempData = data
this.tempFormat = "DETAIL"
return process()
}
private fun process(): String {
return when (tempFormat) {
"SUMMARY" -> "Summary of $tempData"
"DETAIL" -> "Detail of $tempData"
else -> ""
}
}
}
-
tempDataとtempFormatは 一時的にしか使われないフィールド - クラスに残り続け、読み手に混乱を与える
After①:メソッドオブジェクト化
class ReportGenerator {
fun generateSummary(data: String) =
ReportTask(data, "SUMMARY").process()
fun generateDetail(data: String) =
ReportTask(data, "DETAIL").process()
}
private class ReportTask(
val data: String,
val format: String
) {
fun process(): String =
when (format) {
"SUMMARY" -> "Summary of $data"
"DETAIL" -> "Detail of $data"
else -> ""
}
}
→ 一時フィールドを ReportTask に閉じ込め、ReportGenerator はシンプルに。
After②:ローカル変数化(単純ケース)
class ReportGenerator {
fun generateSummary(data: String): String {
val format = "SUMMARY"
return process(data, format)
}
fun generateDetail(data: String): String {
val format = "DETAIL"
return process(data, format)
}
private fun process(data: String, format: String): String =
when (format) {
"SUMMARY" -> "Summary of $data"
"DETAIL" -> "Detail of $data"
else -> ""
}
}
→ フィールド不要、ローカル変数で十分。
13.4 実務での指針
- 一時的にしか使わないフィールドは匂い
- 「そのフィールドはこのクラスに本当に属しているか?」を問い直す
- null チェックが多発 → クラス分割を検討
- 複雑処理のためだけに存在するなら メソッドオブジェクト化 を適用
まとめ
- Temporary Field は「クラスが余計な責務を抱えているサイン」
- 解決策は Extract Class / Introduce Method Object / ローカル変数化
- 基本思想:クラスは「常に意味を持つフィールドだけ」を持つべき