0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【リファクタリング】Replace Type Code with Subclasses(型コードをサブクラスに置き換える)

Posted at

1. 概要(Overview)

Replace Type Code with Subclasses は、型コード(数値や文字列など)によって分岐処理を行っている場合に、
その型コードを サブクラス に置き換えるリファクタリングです。

目的

  • 型コードによる ifwhen/switch 文を削除
  • 振る舞いを 多態性(ポリモーフィズム) に移し、分岐をなくす
  • 新しい種類の追加を サブクラス追加 で表現できるようにする

2. 適用シーン(When to Use)

  • クラスに「type」というフィールドがあり、when(type)if(type==X) で分岐している
  • 分岐処理がクラスのあちこちに散らばっている
  • 「型コードごとに違う振る舞い」がある
  • 新しい種類を追加するたびに、既存クラスに if/when を追加して修正が必要になる

よくある匂い:

  • Type Code(型コード)
  • Switch Statements(スイッチ文)
  • Shotgun Surgery(散弾銃のような変更)

3. 手順(Mechanics / Steps)

  1. 型コードを保持しているフィールドを特定
  2. クラス階層を導入し、型コードごとにサブクラスを作成
  3. 型コードによる分岐を、サブクラスの多態メソッドに移す
  4. ファクトリメソッドを導入して、クライアントからは型コードを隠す
  5. 分岐が消えたら型コードフィールドを削除

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 は「型コード + 分岐」を 継承とポリモーフィズム に置き換えるリファクタリング
  • 判断基準:種類ごとに異なる振る舞いを持っているか?
  • 基本思想:分岐ではなく、多態性で種類ごとの違いを表現する

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?