C++やJavaを使っているとついついクラスを継承してしまいがちになってしまう。継承は親クラスの機能をすべて使うことのできる強力な機能である。でも本当に必要なのかちゃんと考えなければならない。
まず、IS-A関係になっているか。また「リスコフの置換原則(The Liskov Substitution Principle,LSP)」に反していないか。これは親クラス型の変数に継承した子クラスのインスタンスを代入しても問題なく使えるかということ。
親クラスの一部の機能しか使っていないようなら、継承ではなく委譲に置き換える。
class Parent { void method() { ... } ... } class Child : public Parent { ... }
Parentを継承してChildを作っていたのを次のように委譲に置き換える。
class Child { Parent delegate = new Parent(); ... void method() { delegate.method(); } }
手順
- 子クラスに親クラス型の委譲用フィールドを追加
- 委譲用フィールドをコンストラクタ内でthisで初期化
- 継承していたメソッドを委譲用フィールドを使うように書き換え
コンパイルしてテスト。
- 継承の宣言を削除
- 委譲用フィールドを親クラスのインスタンスで初期化
- 外部から利用されていたメソッドを委譲用フィールドを使った形で追加
コンパイルして確認。
継承を委譲に置き換えたときに気になるのはメモリと速度。委譲用フィールドが必要になるし、メソッドの呼び出しも一段階増えてしまう。まあ機能が限定された組み込み系とかでは問題になるかもしれないけど、普通のPCでは問題にはならないだろう。
今までプログラミングしてきて、委譲を使うことを考えることがあまりなかった。これからは委譲を使うことも選択肢の一つとして考えていきたい。