1. 概要(Overview)
Replace Type Code with Subclasses は、型コード(数値や文字列など)によって分岐処理を行っている場合に、
その型コードを サブクラス に置き換えるリファクタリングです。
目的:
- 型コードによる
ifやwhen/switch文を削除 - 振る舞いを 多態性(ポリモーフィズム) に移し、分岐をなくす
- 新しい種類の追加を サブクラス追加 で表現できるようにする
2. 適用シーン(When to Use)
- クラスに「type」というフィールドがあり、
when(type)やif(type==X)で分岐している - 分岐処理がクラスのあちこちに散らばっている
- 「型コードごとに違う振る舞い」がある
- 新しい種類を追加するたびに、既存クラスに
if/whenを追加して修正が必要になる
よくある匂い:
- Type Code(型コード)
- Switch Statements(スイッチ文)
- Shotgun Surgery(散弾銃のような変更)
3. 手順(Mechanics / Steps)
- 型コードを保持しているフィールドを特定
- クラス階層を導入し、型コードごとにサブクラスを作成
- 型コードによる分岐を、サブクラスの多態メソッドに移す
- ファクトリメソッドを導入して、クライアントからは型コードを隠す
- 分岐が消えたら型コードフィールドを削除
4. Kotlin 例(Before → After)
Before:型コードと when による分岐
class Employee(val name: String, val type: Int) {
companion object {
const val ENGINEER = 0
const val MANAGER = 1
const val SALESMAN = 2
}
fun payAmount(): Int {
return when (type) {
ENGINEER -> 3000
MANAGER -> 5000
SALESMAN -> 2000
else -> throw IllegalArgumentException("Unknown type")
}
}
}
-
typeフィールドとwhenによる分岐が散在 - 新しい種類を追加すると、既存クラスのコードを修正する必要がある
After:サブクラスに置き換え
abstract class Employee(val name: String) {
abstract fun payAmount(): Int
companion object {
fun createEngineer(name: String): Employee = Engineer(name)
fun createManager(name: String): Employee = Manager(name)
fun createSalesman(name: String): Employee = Salesman(name)
}
}
class Engineer(name: String) : Employee(name) {
override fun payAmount(): Int = 3000
}
class Manager(name: String) : Employee(name) {
override fun payAmount(): Int = 5000
}
class Salesman(name: String) : Employee(name) {
override fun payAmount(): Int = 2000
}
fun main() {
val alice: Employee = Employee.createEngineer("Alice")
val bob: Employee = Employee.createManager("Bob")
println("${alice.name} earns ${alice.payAmount()}")
println("${bob.name} earns ${bob.payAmount()}")
}
-
when(type)が不要になり、多態性で表現 - 新しい種類を追加する場合は、サブクラスを作るだけ
5. 効果(Benefits)
-
if/whenの分岐を排除 → 可読性・保守性向上 - 新しい種類を追加する際に 既存コードを変更しなくてよい(OCP: Open/Closed Principle に適合)
- 振る舞いをサブクラスに閉じ込められる → 凝集度が高まる
6. 注意点(Pitfalls)
- クラス数が増えるので、小規模な場合は逆に冗長になる
- 型コードが「単なる属性」で振る舞いを伴わない場合は、
enum classの方が適切 - 「種類追加より種類変更が頻繁」なケースではメリットが薄い
まとめ
- Replace Type Code with Subclasses は「型コード + 分岐」を 継承とポリモーフィズム に置き換えるリファクタリング
- 判断基準:種類ごとに異なる振る舞いを持っているか?
- 基本思想:分岐ではなく、多態性で種類ごとの違いを表現する