はじめに
ソフトウェア開発では「再利用性を高めるための抽象化や継承」を行うことが多いですが、
必要以上に一般化すると以下の問題が発生します:
- 無駄に複雑になり、コードの可読性・理解コストが上がる
- 変更時に影響範囲が広がり、保守が難しくなる
- 実際には不要な抽象クラスやインターフェースが増える
そこで「一般化のやりすぎ」を是正するリファクタリングが Dealing with Generalization です。
代表的な手法(Techniques)
1. Pull Up Field / Method / Constructor Body
- 目的: 共通部分を親クラスへ移動し、重複を減らす
- 適用場面: 複数のサブクラスに同じフィールド・メソッド・コンストラクタ処理があるとき
2. Push Down Field / Method
- 目的: 親にあるが、特定のサブクラスでしか使わないフィールドやメソッドを下げる
- 適用場面: 共通化のしすぎで無駄に親に入っているものを整理
3. Extract Subclass / Superclass / Interface
- Extract Subclass: 特殊な動作を持つ一部のオブジェクトをサブクラス化して整理
- Extract Superclass: 複数クラスの共通処理をまとめて親を作る
- Extract Interface: 共通APIを定義して依存方向を整理
4. Collapse Hierarchy
- 目的: 抽象クラスとサブクラスの差がほとんどなくなったとき、統合して簡素化する
- 効果: クラス階層をスリム化
5. Form Template Method
- 目的: サブクラス間で似た処理があるとき、テンプレートメソッドパターンで共通化する
-
例:
- 共通部分を親クラスに置き、差分だけを抽象メソッドとしてサブクラスに実装させる
6. Replace Inheritance with Delegation
- 目的: 「is-a」の関係が適切でないときに、継承をやめて委譲に置き換える
- 効果: 不自然な継承を排除し、柔軟性を高める
7. Replace Delegation with Inheritance
- 逆のパターン。もし「完全に is-a の関係」なら、委譲ではなく継承にしたほうがシンプル。
適用の指針
- 共通化のメリット vs 可読性・保守性の悪化 を天秤にかける
- 「再利用できるかもしれない」だけで抽象化しない
- 実際の変更・拡張が出てきたときに抽象化を導入するのがベスト
まとめ
- 「Dealing with Generalization」は、過剰な抽象化を整理したり、不足している共通化を導入したりして、
クラス階層を適切に保つリファクタリング群 - 代表的な技法には Pull Up / Push Down / Extract / Collapse / Replace がある
- 抽象化の目的は「将来の変更容易性」であり、過剰な一般化は逆に負債になる