はじめに
Simplifying Method Calls は、メソッドの呼び出しをより直感的で使いやすくするためのリファクタリングの総称です。
メソッド呼び出しが複雑だったり、引数の数が多すぎたり、名前が分かりにくい場合、
呼び出す側のコードが読みにくくなり、誤用やバグを招きやすくなります。
目的は以下の通りです:
- API の使いやすさを高める
- コードの意図を明確にする
- 複雑な呼び出しをシンプルにしてメンテナンス性を向上
代表的なテクニック
1. Rename Method(メソッド名の変更)
- 目的:メソッドの意図をより分かりやすい名前にする
-
例:
getData()→fetchCustomerOrders()
2. Add Parameter / Remove Parameter(パラメータの追加・削除)
- 目的:メソッド呼び出しに必要な情報を調整する
- 例:不要になった引数を削除、逆に必要な情報を引数として追加
3. Introduce Parameter Object(パラメータオブジェクトの導入)
- 目的:長い引数リストをまとめて可読性を改善
-
例:
createUser(name, age, email, phone)→createUser(UserInfo)
4. Preserve Whole Object(オブジェクト全体を渡す)
- 目的:複数のフィールドをバラバラに渡す代わりに、オブジェクトをそのまま渡す
-
例:
calculate(area.width, area.height)→calculate(area)
5. Replace Parameter with Explicit Methods(引数を明示的メソッドに置き換え)
- 目的:フラグ引数をやめ、意図ごとに別メソッドを作る
-
例:
printReport(detailed: Boolean)→printDetailedReport()/printSummaryReport()
6. Parameterize Method(メソッドのパラメータ化)
- 目的:重複している複数メソッドを、パラメータで共通化する
-
例:
fivePercentDiscount()とtenPercentDiscount()→discount(rate: Double)
7. Remove Setting Method(設定用メソッドの削除)
- 目的:不変性を保つために、セッターメソッドを削除する
-
例:
setName("Alice")→ コンストラクタでのみ設定可能にする
8. Hide Method(メソッドの隠蔽)
-
目的:外部から使われるべきでないメソッドを
privateにする - 効果:API のシンプル化、誤用の防止
9. Replace Constructor with Factory Method(コンストラクタをファクトリーメソッドに置き換え)
- 目的:生成処理を分かりやすくする、複雑な生成を隠蔽する
-
例:
User("Alice")→User.createWithDefaultRole("Alice")
10. Replace Error Code with Exception(エラーコードを例外に置き換え)
- 目的:戻り値でエラーを表現せず、例外を使って呼び出しをシンプルにする
-
例:
if (result == -1) ...→throw IllegalArgumentException()
11. Replace Exception with Test(例外をテストで置き換え)
- 目的:例外を通常フローで使わず、事前チェックで防ぐ
-
例:
- Before:
try { list.get(0) } catch (IndexOutOfBoundsException e) { … } - After:
if (list.isNotEmpty()) list[0]
- Before:
Kotlin 例(Before → After)
Before:フラグ引数が分かりにくい
class Report {
fun printReport(detailed: Boolean) {
if (detailed) {
println("Detailed Report...")
} else {
println("Summary Report...")
}
}
}
fun main() {
val report = Report()
report.printReport(true) // true が何を意味するのか分かりにくい
}
After:メソッドを分割して意図を明確化
class Report {
fun printDetailed() {
println("Detailed Report...")
}
fun printSummary() {
println("Summary Report...")
}
}
fun main() {
val report = Report()
report.printDetailed() // 意図が明確
}
Before:長い引数リスト
fun createUser(name: String, age: Int, email: String, phone: String) {
println("User: $name, $age, $email, $phone")
}
fun main() {
createUser("Alice", 30, "alice@example.com", "123-456")
}
After:引数をオブジェクト化
data class User(val name: String, val age: Int, val email: String, val phone: String)
fun createUser(user: User) {
println("User: $user")
}
fun main() {
val user = User("Alice", 30, "alice@example.com", "123-456")
createUser(user)
}
効果(Benefits)
- メソッド呼び出しが 直感的で分かりやすい
- API の誤用が減る(フラグの意味を忘れるなどの問題を防止)
- クライアントコードがシンプルになる
- 拡張性が上がり、将来的な変更に強くなる
注意点(Pitfalls)
- メソッドを分割しすぎると逆に API が散らばって分かりにくくなる
- 過度に抽象化すると、逆に「何をするメソッドなのか」が不明確になる
- 引数削減のために過剰なオブジェクト化をすると、データクラスが乱立する
まとめ
- Simplifying Method Calls は「複雑なメソッド呼び出しをより使いやすく整理する」リファクタリング
- 判断基準:そのメソッド呼び出しは直感的に理解できるか?
- 基本思想:API は「読む人・使う人」にとって自然であるべき