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 Subclass with Fields(サブクラスをフィールドに置き換える)

Posted at

1. 概要(Overview)

Replace Subclass with Fields は、サブクラスの違いが 単なる定数値の違い にすぎない場合、
サブクラスをやめて フィールド(プロパティ) にまとめるリファクタリングです。

目的

  • 不要に増えすぎたサブクラスを整理
  • 継承をやめてシンプルに
  • 可読性と保守性を向上

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

  • サブクラス間の違いが 定数値(名前、料金、種類など)だけ
  • 振る舞い(メソッド)は同じで、データの違いしかない
  • 新しい種類を追加するときに サブクラスを増やすのが冗長
  • 継承ツリーが複雑化している

よくある匂い:

  • Speculative Generality(過剰な一般化)
  • Parallel Inheritance Hierarchies(並行した継承階層)

3. 手順(Mechanics / Steps)

  1. サブクラス間の違いが「定数値」にすぎないことを確認
  2. スーパークラスにフィールドを追加
  3. サブクラスごとに異なっていた値を、そのフィールドに割り当てる
  4. サブクラスを削除し、インスタンス生成時に値を設定する
  5. ファクトリメソッドを導入して利用側の可読性を確保

4. Kotlin 例(Before → After)

Before:サブクラスで表現

abstract class Person(val name: String)

class Male(name: String) : Person(name)
class Female(name: String) : Person(name)

fun main() {
    val alice: Person = Female("Alice")
    val bob: Person = Male("Bob")

    println("${alice.name} is Female")
    println("${bob.name} is Male")
}
  • サブクラスの違いは「性別」だけ
  • 振る舞いはすべて同じ → サブクラスが冗長

After:フィールドに置き換え

class Person(val name: String, val gender: Gender)

enum class Gender { MALE, FEMALE }

fun main() {
    val alice = Person("Alice", Gender.FEMALE)
    val bob = Person("Bob", Gender.MALE)

    println("${alice.name} is ${alice.gender}")
    println("${bob.name} is ${bob.gender}")
}
  • Gender フィールドで違いを表現
  • サブクラス不要、シンプルで拡張しやすい

After②:ファクトリメソッドを導入

class Person private constructor(val name: String, val gender: Gender) {
    companion object {
        fun male(name: String) = Person(name, Gender.MALE)
        fun female(name: String) = Person(name, Gender.FEMALE)
    }
}

enum class Gender { MALE, FEMALE }

fun main() {
    val alice = Person.female("Alice")
    val bob = Person.male("Bob")

    println("${alice.name} is ${alice.gender}")
}

生成意図が明確 になり、可読性がさらに向上。


5. 効果(Benefits)

  • サブクラス乱立を防ぎ、設計がシンプル
  • 継承階層が浅くなり、可読性・保守性が向上
  • 新しい種類の追加が容易(サブクラス追加 → enum/フィールド値追加で済む)
  • データと生成方法を集中管理できる

6. 注意点(Pitfalls)

  • 本当に「データの違いだけ」かを確認する(振る舞いも異なるなら Replace Type Code with Subclasses の方が適切)
  • enum/フィールドに寄せすぎると God Class 化 のリスクがある
  • 新しい種類ごとに異なるロジックが将来追加されそうなら、Strategy/State パターン を検討

まとめ

  • Replace Subclass with Fields は「違いが値だけのサブクラス」を フィールドにまとめる リファクタリング
  • 判断基準:このサブクラスの違いは振る舞いか?データか?
  • 基本思想:データの違いに過ぎないなら、フィールドで十分

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?