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 Class (型コードをクラスに置き換える)

Posted at

1. 概要(Overview)

Replace Type Code with Class は、定数や数値で表現している「型コード(type code)」を、
明示的なクラス に置き換えるリファクタリングです。

例:

  • 「1 = エンジニア, 2 = マネージャー」などの 数字
  • "S""P" などの 文字列コード

こうした「マジックコード」は意味が不明瞭で、比較や変更に弱いです。
専用クラスに置き換えることで:

  • 意味を明示化
  • 不正値を防止
  • 振る舞いを追加可能

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

  • 数字や文字列を 型コード(識別子) として使っている
  • if/switch 文で型コードを分岐している
  • 「型コードに応じた振る舞い」を拡張したい
  • 意図しない値(999"X")が入り込む危険がある

よくある匂い:

  • Magic Number / String(マジックナンバー/文字列)
  • Primitive Obsession(基本型執着)

3. 手順(Mechanics / Steps)

  1. 型コードを使っているフィールドや定数を特定
  2. それを表す新しいクラスを導入
  3. 型コードをそのクラスのインスタンスに置き換える
  4. クライアントコードを修正して、新しいクラスを利用するようにする
  5. 必要なら、そのクラスに振る舞いを追加

4. Kotlin 例(Before → After)

Before:型コードを int で管理

class Employee(val name: String, val type: Int) {
    companion object {
        const val ENGINEER = 0
        const val MANAGER = 1
        const val SALESMAN = 2
    }
}

fun main() {
    val alice = Employee("Alice", Employee.ENGINEER)
    if (alice.type == Employee.ENGINEER) {
        println("${alice.name} is an engineer")
    }
}
  • 0, 1, 2 の数字が「職種コード」として使われている
  • 意味が分かりにくく、不正な値(999)も入り込める

After:クラスに置き換え

class EmployeeType private constructor(val name: String) {
    companion object {
        val ENGINEER = EmployeeType("Engineer")
        val MANAGER = EmployeeType("Manager")
        val SALESMAN = EmployeeType("Salesman")
    }

    override fun toString(): String = name
}

class Employee(val name: String, val type: EmployeeType)

fun main() {
    val alice = Employee("Alice", EmployeeType.ENGINEER)
    println("${alice.name} is a ${alice.type}")
}
  • 型コードを EmployeeType クラスにまとめて明示化
  • 不正な値を使えなくなり、意図が明確になる

After②:振る舞いを型クラスに追加

class EmployeeType private constructor(val title: String) {
    companion object {
        val ENGINEER = EmployeeType("Engineer")
        val MANAGER = EmployeeType("Manager")
        val SALESMAN = EmployeeType("Salesman")
    }

    fun calculateOvertimePay(hours: Int): Int {
        return when (this) {
            ENGINEER -> hours * 20
            MANAGER -> hours * 30
            SALESMAN -> hours * 10
            else -> 0
        }
    }

    override fun toString(): String = title
}

class Employee(val name: String, val type: EmployeeType) {
    fun overtimePay(hours: Int): Int = type.calculateOvertimePay(hours)
}

→ 型コードに応じたロジックを EmployeeType に集約可能。


5. 効果(Benefits)

  • マジックナンバー/文字列を排除して 意図が明確に
  • 不正値を防止できる(型安全)
  • 型コードごとの振る舞いをクラスにまとめられる
  • Primitive Obsession を解消し、ドメインモデルがリッチに

6. 注意点(Pitfalls)

  • 小規模・一時的なコードに適用すると冗長になる
  • 定数だけなら enum class の方が適切な場合も多い
  • 拡張可能性が不要なら、まずは enum を検討する

まとめ

  • Replace Type Code with Class は「数字や文字列コードを明示的なクラスに置き換える」リファクタリング
  • 判断基準:その型コードは不正値を防ぎ、振る舞いを追加する価値があるか?
  • 基本思想:意味ある概念はクラスで表現し、コードを自己文書化する

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?