katzeの日記: 委譲と継承
オブジェクト指向設計において、分析段階で導き出された汎化-特化関係を展開する場合、委譲と継承のどちらかを使うことになる。
#分析段階の汎化-特化関係はあくまでもそのドメインの中に存在する
概念同士の関係がいかなるものであるかを見るためのものであって実装(≒設計)とは直接関係しない。
#で、実際には継承ではなくインターフェイスにする、という第3の選択肢もあるがその辺は都合により省略。
最近の自分の中の流行としては継承よりも委譲を使う場合のほうが圧倒的に多い。
というのは、継承の場合異なるパッケージにスーパークラスとサブクラスが分離して配置された場合にパッケージ間の強い依存関係が出来上がってしまったり、本来変更しないはずのスーパークラスを変更せざるを得ない場合にサブクラスへの影響を考慮しなければならなかったりして不用意に使うのがためらわれるからだ。
もちろん、スーパークラスの変更についてはprotectedを安易に使わずにメソッド経由で属性にアクセスするとかそういうルールを厳密に定めてこれに従うことにより影響を最小化する、でもいいのだが、メンテナンスをする人間がそこまで注意深くコードを読んでくれるか?という問題もあったりしていろいろ難しい。
委譲は通常の関連と同じ実装になる。
委譲の場合は、継承において差分プログラミングによって重複実装を省くのではなく、そのクラスに対するメッセージ呼び出しを行うことによって重複実装を省くという考え方である。
何のことはない、分析段階では汎化-特化関係にあると判断されても実は単なる関連だった、というわけである。
もちろん、関連を持つ以上依存関係は発生するわけだが継承ほどは強くないし、間にインターフェイスや抽象クラスを挟むことによってより依存度を弱めることも可能だ。
クラスの公開されたインターフェイスのみを使用するので委譲したクラスの内容がどう変わろうと影響はそのクラスの中のみで最小化される。
つまり継承における悩みが解消されることになるのだ。
その反面、分析と設計の間のトレーサビリティが崩れるという問題がある。
これもやはりメンテナンス時に問題になりやすいが、間抜けなメンテナが勝手に委譲を継承に作り変えたりしなければ大きな問題にはならない、というか今のところなっていない。
また、委譲の場合はpolymorphismが働いてくれないので(.NETの場合はdelegateがあるからこの限りではない)polymorphismを生かして拡張の柔軟性をもたらそうとする場合は不向きである。
そもそもオブジェクト指向というのは継続開発またはメンテナンス時にもっとも効力を発揮する、というのがおれの持論なので、システムが定常運用され、メンテナンスされるところまでを踏まえてついつい考えてしまう。
となると継承と委譲とはそれぞれ使い道が違うのでそれほど大きく混乱することはないがこれを他人(同僚やら新人やら顧客やら)に説明するときにいまいちピンとくる説明ができないのが悩みの種。
結局自分でやってみて勘所をつかむ他はないのかなあ...
委譲と継承 More ログイン