要点
- 「継承より委譲」という表現がよく使われるが、原義は “Favor Composition over Inheritance” — 「継承より合成を優先する」である。
- has-a(オブジェクトを保持する)という構造は「委譲」ではなく「合成(Composition)」と呼ぶ方が誤解が少ない 1。
- Composition は構造(has-a)、Delegation は設計手法、Forwarding はその実装である。
GoF の定義
GoF は次のように述べている。
Delegation is a way of making composition as powerful for reuse as inheritance.
(委譲は、合成を継承と同じくらい強力な再利用手段にする方法である)— Design Patterns: Elements of Reusable Object-Oriented Software
合成(has-a)だけでは構造の関係に留まるが、委譲を組み合わせることで振る舞いの再利用が可能になる。これが「継承より合成」の本質である 2。
3 つの概念
| レイヤー | 概念 | 説明 |
|---|---|---|
| 構造設計 | Composition(合成) | has-a 関係。オブジェクトを保持する構造 |
| 設計手法 | Delegation(委譲) | 自身の責務の一部を、保持したオブジェクトに任せる |
| 実装 | Forwarding(転送) | 呼び出しを転送するコード |
Delegation は文献によって使い方が揺れる。Forwarding と混用されることも多い 3。
コード例
|
|
合成による再利用(has-a)
|
|
Car は Engine を保持し(合成)、start() の責務を任せ(委譲)、engine.start() を呼び出す(転送)。3 つのレイヤーがそれぞれ異なる役割を担っている。
Engine の実装を差し替え可能にすれば、テスト容易性も向上する。
継承による再利用(is-a)
|
|
super.start() は継承階層内の呼び出しであり、別のオブジェクトに責務を任せているわけではない。これは委譲ではない。
まとめ
「継承より委譲」ではなく「継承より合成」が原義である。
- 合成(Composition) は構造の話(has-a)
- 委譲(Delegation) は合成と組み合わせて再利用を可能にする設計手法
- 転送(Forwarding) はその実装
この 3 つを区別するだけで、設計の議論における用語の曖昧さは大きく減る。