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?

【リファクタリング】Push Down Field(フィールドの押し下げ)

Posted at

1. 概要(Overview)

Push Down Field は、スーパークラスに定義されているフィールドを、
実際に必要なサブクラスへ移動(押し下げ) するリファクタリングです。

スーパークラスは共通の抽象を表すべきですが、現実には 一部のサブクラスだけが使う状態(フィールド) が混入しがちです。
その場合、当該フィールドを必要なサブクラスに移すことで、階層の責務が明確になります。

目的は以下の通り:

  • スーパークラスをより抽象的・汎用的に保つ
  • サブクラス固有の状態をサブクラス側に隔離する
  • 継承階層の可読性・保守性を向上させる

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

  • スーパークラスのフィールドが 一部のサブクラスでしか参照されていない
  • フィールドが特定サブクラスのふるまい・制約に強く依存している
  • 「共通の状態」を装っているが、実は 汎用性がない(=抽象の侵食)

よくある匂い:

  • Refused Bequest(不要な継承)
  • Large Class(巨大クラス)
  • Intimacy between classes(不適切な親密さ):不要な protected 共有など

3. 手順(Mechanics / Steps)

  1. 対象フィールドを特定(実際にどのクラスが使っているかリファレンスを確認)
  2. フィールドを 必要なサブクラス に移動
  3. それに伴う アクセサ/依存メソッド を合わせて押し下げ(必要なら Push Down Method も併用)
  4. スーパークラスからフィールドを削除
  5. テストで動作確認(生成・参照・シリアライズなどもチェック)

4. Kotlin 例(Before → After)

Before:共通クラスにサブクラス専用フィールドがある

open class Employee(
    val name: String
) {
    // 実は営業にしか使われない
    protected var salesRegion: String? = null
}

class Engineer(name: String) : Employee(name)

class Salesman(name: String) : Employee(name) {
    fun assignRegion(region: String) {
        this.salesRegion = region
    }

    fun canVisit(region: String): Boolean {
        return salesRegion == region
    }
}
  • salesRegionSalesman だけが使うのに Employee に存在
  • Engineer にとって不要な状態が見えてしまう(責務の混在)

After:必要なサブクラスへフィールドを「押し下げ」

open class Employee(
    val name: String
)

class Engineer(name: String) : Employee(name)

// 営業にだけ必要な状態はサブクラスに閉じ込める
class Salesman(name: String) : Employee(name) {
    private var salesRegion: String? = null

    fun assignRegion(region: String) {
        this.salesRegion = region
    }

    fun canVisit(region: String): Boolean {
        return salesRegion == region
    }
}
  • salesRegionSalesman へ移動
  • Engineer から不要な状態が消え、Employee はより抽象的に
  • アクセス修飾子も private にでき、カプセル化が向上

5. 効果(Benefits)

  • スーパークラスから サブクラス固有の状態 が排除され、抽象がクリアに
  • 不要な protected 共有が減り、カプセル化が強化
  • 継承階層の意図が読みやすくなり、保守性とテスト容易性 が向上

6. 注意点(Pitfalls)

  • 複数サブクラスが同じフィールドを必要とするなら、押し下げではなく Pull Up Field で共通化を検討
  • 押し下げに伴い、関連メソッドやバリデーションも移動が必要(Push Down Method 併用)
  • そのフィールドを使う外部コードがスーパークラス型を前提にしている場合、参照箇所の修正 が発生
  • 継承自体が過剰な場合は、委譲(Composition) への設計転換も検討

まとめ

  • Push Down Field は「スーパークラスの不要なフィールドを、必要なサブクラスへ移す」リファクタリング
  • 判断基準:その状態は本当に全サブクラスに共通か? それとも特定のサブクラスだけの事情か?
  • 基本思想:抽象は軽く、特化は局所化。状態は必要な場所で閉じ込める

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?