とある文章を読んで書きたくなった、継承に対する私の印象
発端
http://qiita.com/koitaro/items/c3720d9c3ac1e7b0590f
荒削りですけど、まぁそうですね、という感じで見ていました。
一言書いてみたくなったのは、『継承はis-a関係』の
親クラス作ってまとめたら重複コード減らせる
具体的な判断の仕方
「親クラスで使っているプロパティ、メソッドを全て使える状態であるか」
この辺りですね。
『差分プログラミング』
継承に対する誤解を一番よく表現しているのはこの言葉ではないかなと。
デザインパターンも知られていなかった1990年代頃、当時私も学生でしたが、継承は専らこのコンテキストでもてはやされることが多かったんですよね。
おそらく『構造化プログラミング』からのアナロジーで継承を理解しようとした事による弊害なんだろうなぁ、と今となっては思います。
サブクラスとスーパークラスの可換性についてももちろん説明しようとはするのですが、自動車とトラックとか、動物と犬とか訳の分からない抽象論で終わってしまう所、
『おぉ、継承使えばプログラミングする手間が減って楽じゃん』
という即物的、安直的なメリットの示し方をしてしまった結果かなと。
個人的な経験上、デザインパターンを知ってから継承に対する考え方が180度変わったので、後述する可換性や接合点について、具体的なメリットと好設計例を示せれば、多分この手の誤解を減らすことはできるんじゃないかなぁという感もあります。 *1
『リスコフの置換規則』
上の判断でもそんなにおかしなことにはならないとは思いますが、もう少し厳密な原則で行くならこれかなと。
http://d.hatena.ne.jp/asakichy/20090127/1233109959
『スーパークラスと同一の取扱いをしてもよいか、むしろ同一の取扱いをすべき時にサブクラス化する』
というのが私が継承を使う時の一つの基準です。
接合点
あと、継承は『接合点(インタフェース)を合わせるための手段』だと認識している、というのもあるかなと。
デザインパターンで継承を使う最大の理由ってコレじゃないですか。
他にもモックやらスタブやら、OOPでテストダブルを使いはじめると、いやでもインタフェースを合わせないといけなくなるので、この辺の着想には到達しやすいかもしれません。
まとめ?
部品として使うだけだったら、とりあえずはHas-a(内部クラスや別クラスへの切り出し)を使っておきましょう。
無理して継承を使わなくても、
- 適切な粒度の機能を一つのクラスにまとめ
- インタフェースとして出すものは出し
- 中でしか使わないものは隠す
という基本を実施するだけで、機能的、情報的強度を確保できるので、ちゃんと再利用性も得られます。
今はOOPの原則は充実しているので、継承は差分プログラミング以外の動機にハラオチしてから使うのがいいのではないかしら、という感想でした。
*1: 個々の素養:抽象化力の影響は、当然あるのでしょうけど。