前回記事の続きになります。
今回は「継承」について見ていきます。
2 継承
継承は、いわゆる三大柱の中では一見すると一番わかりやすいと感じると思います。
なぜかというと、継承すると起きることが目に見える上わかりやすいからです。
親クラスの変数やメソッドを子クラスでも使用できるようになるということです。
これによって、複数のクラス全部に書いていた変数やメソッドを、親クラスに1回書けばいいのでとても楽です。
しかし、だからこそ安易に使用しまくって、めちゃくちゃなクラスが出来上がりがちなようです。
それでは継承の目的やメリット、どういう時に使えばいいのかを見ていきましょう。
2.1 継承の利点
基本的に、あちこちのコードに同じことが書いてあると文字数が増えてわかりにくいですよね。
このわかりやすさを追求すると、便利に使えて、かつ変更に強くなるのです。
2.1.1 変更に対応しやすくなる
複数のクラスに全部書いてるようなメソッドを直さないといけない! となった時、親クラスにまとめていないと、まずはどのクラスにそのメソッドを書いていたかを全部探し尽くして、1つ残さず直さないとなりません。
1つでも漏らしたらバグが生じます。
しかし、親クラスにまとめていれば、1箇所直したらそれでオッケーです。
例えば「自動車」というクラスがあったとして、自動車にも技術革新はつきものですから新しいパーツを導入していく必要があるわけです。
もし10種類の自動車クラスを製造していたとして、エンジンというパーツを各クラスで定義していた場合、新型エンジンに交換しようとすると全クラス書き換えが必要です。
こういう頻繁に取り替えたい部品を親クラスにまとめてしまうことで、簡単に取り替えが可能になるのです。
2.1.2 機能拡張しやすくなる
これは次回説明するポリモーフィズムにも通ずる考え方になります。
例えば子クラスの部品を取り替えるだけではなく、親クラスにぶら下がっている子クラスを簡単に増やしたり減らしたりできるようになります。
また、プログラムを作成している時に、最初から全貌が確定しているわけではないと思います。
そうなると「こういう種類のもの」を作るだろうなという「抽象的」なことはわかっていて作業をするわけですが、より詳細な内容はあとあと変更があるかもしれません。
例えば「自動車」を作ることは決まっていて、とりあえずセダンと軽トラは作ろう。ミニバンもやるかもしれないし、ジープも作りたいけど、その詳細までは決まっていないような感じです。
そんな時に、自動車に共通する規格ーー例えば、タイヤ、ハンドル、シート、エンジンなどを部品として先に作ってまとめておけば、あとで車種を増やした時にも基本パーツはある程度揃った状態で増やせるわけです。
いざミニバンも作ろう! と思ったら、規格品であるハンドルやエンジンは親クラスから継承して、ミニバン用のシャーシとか、ボディとかだけを作ればよくなります。
###2.2 継承 = 共通部品を取り出して「規格」を作る
継承には親クラスと子クラスを**「共通部分(規格)」で繫ぎとめるような「結節点」**を作る役割があると言えます。
子クラスから見れば、他の子クラスとの「共通部品」を束ねて繋ぎ止めてくれる存在が親クラスです。
親クラスにお願いすれば、みんなの共通部品を一気に書き換えできます。
親クラスから見ると、親クラスに記載されている定義を共有している、脱着可能な構造をいくつもぶら下げているような感じです。
「まだ思いついてないけど共通の部品」を持つものにも対応できてしまう柔軟性があります。
このような便利な継承ですが、やってはいけない継承とはどのような場合でしょうか?
それは、継承を「親の機能を流用できる」機能と勘違いしてされる継承です。
2.3 破ってはいけない「AはBであるの原則」
破ってはいけない原則として**「子クラスは親クラスである」**というものがあります。
例えば「自動車」という親クラスがあって、その中に「走る」というメソッドがあったとします。
でもその機能の一部を使い回したい目的で「犬」というクラスに「自動車」クラスを継承したらどうでしょうか。
最初はいいかもしれませんが、「走る」メソッドは自動車用に作られていくため、犬には適合しないはずです。
犬用に修正すると自動車に合わない、自動車用に修正すると犬に合わなくなり破綻します。
あくまで継承の目的は「頻繁に変更する共通部品の抽象化」 であって「抽象化」できないものは継承できません。
なので、種類の異なる親クラスの一部機能を他クラスでもちょっと使いたいから継承、というのは良くないのです。
2.4 まとめ
- 継承すると子クラスで親クラスの変数やメソッドを使うことができる
- 継承の大前提は「子クラスは親クラスである」と言えること
- 継承とは「共通部品」を束ねて規格化することであって、親クラスの機能を流用する目的ではない。
- 継承することによって、共通部品の修正交換が簡単になるなど、「変更」に強くわかりやすいプログラムになる。