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?

【リファクタリング】Extract Subclass(サブクラスの抽出)

Posted at

1. 概要(Overview)

Extract Subclass は、既存のクラスの中に 特定の機能やフィールドが一部のインスタンスでしか使われていない 場合に、
その部分を新しいサブクラスへ切り出すリファクタリングです。

「大きすぎるクラス(Large Class)」や「複数の責務を持っているクラス」を整理する時に有効です。

目的は以下の通り:

  • クラスの責務を分離し、シンプル化 する
  • 一部のオブジェクトにしか不要なメンバを整理
  • 共通部分はスーパークラスに残し、差分をサブクラスへ

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

  • クラスが 大きすぎて複雑化 している
  • フィールドやメソッドの一部が 特定のケースにしか使われていない
  • その結果、クラスが「if文やnullチェックだらけ」になっている
  • 派生的な概念が見えてきているが、まだ明確に分離されていない

よくある匂い:

  • Large Class(巨大クラス)
  • Divergent Change(分岐的変更)
  • Refused Bequest(不要な継承)(逆パターンの検討要因にもなる)

3. 手順(Mechanics / Steps)

  1. クラスの中から、特定の条件でしか使われないフィールド/メソッドを特定
  2. 新しいサブクラスを作成
  3. 特定の責務をサブクラスへ移動(Push Down Field / Push Down Method の応用)
  4. 元クラスをスーパークラスとし、共通部分を残す
  5. クライアントコードを新しいサブクラスに切り替え

4. Kotlin 例(Before → After)

Before:1つのクラスに全責務を詰め込んでいる

open class Employee(
    val name: String,
    val type: String, // "engineer" or "salesman"
    val commission: Double? = null // 営業だけが使う
) {
    fun calculatePay(): Double {
        return if (type == "salesman") {
            basePay() + (commission ?: 0.0)
        } else {
            basePay()
        }
    }

    private fun basePay(): Double = 3000.0
}
  • commission は営業(salesman)専用なのに Employee 全体で保持
  • calculatePay() が if で分岐し、責務が混在している

After:サブクラスを抽出

open class Employee(
    val name: String
) {
    open fun calculatePay(): Double {
        return basePay()
    }

    protected fun basePay(): Double = 3000.0
}

// エンジニアはシンプル
class Engineer(name: String) : Employee(name)

// 営業は手数料フィールドを追加
class Salesman(name: String, private val commission: Double) : Employee(name) {
    override fun calculatePay(): Double {
        return basePay() + commission
    }
}
  • 共通部分は Employee に残す
  • 営業だけが使う commissionSalesman に移動
  • if 分岐が消え、責務が整理された

5. 効果(Benefits)

  • 大きすぎるクラスを分割し、読みやすくなる
  • サブクラスごとに 責務が明確 になる
  • 条件分岐の削減 により、コードがシンプル化

6. 注意点(Pitfalls)

  • サブクラスを作りすぎると階層が複雑化する
  • 将来的に「共通化した方がよいメソッド」が見つかる場合 → Pull Up Method を併用
  • サブクラス分岐が複雑化するようなら Replace Type Code with Subclasses の導入も検討

まとめ

  • Extract Subclass は「大きなクラスの一部責務を切り出してサブクラス化する」リファクタリング
  • 判断基準:このフィールド/メソッドは全インスタンスで必要か? それとも一部だけ?
  • 基本思想:クラスを役割ごとに整理して、条件分岐や不要な状態をなくす

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?