作成日 2007/5/6 最終更新日 2009/11/1
継承
オブジェクト指向を勉強し、一番最初に理解するのは継承という気がします。本当はクラスとオブジェクトについて理解してから継承について勉強すべきですが…。
継承ってわかりやすいですからね〜。
差分プログラミングなんてクラスやオブジェクトについてまったく理解していなくても理解できちゃうし。
しかし、この「差分プログラミング」というのはおかしいです。何がおかしいかと言うと、処理のことを考えてしまっている。つまり差分プログラミングばかり考えているとPOA(プロセス中心アプローチ)と同じ過ちを繰り返してしまうのではないかと思う。
あと、継承するとスーパークラスとサブクラス間の結合度が強くなるという問題もある。
このページでは、継承とは何か?継承するときの注意について、だるまの考え(というか偏見?)を説明します。
えーと、書くのが面倒なので、とりあえずeword
から引用します。(手抜きです。)
オブジェクト指向プログラミングにおいて、既に定義されているクラスをもとに、拡張や変更を加えた新しいクラスを定義すること。元になるクラスを「スーパークラス」(super
class)、あるいは「基底クラス」「基本クラス」(base
class)などと呼び、新たに定義されたクラスを「サブクラス」(subclass)、あるいは「派生クラス」(derived
class)と呼ぶ。スーパークラスの性質はすべてサブクラスに受け継がれ、サブクラスではスーパークラスとの違いを定義するだけでよい。複数のスーパークラスから新しいクラスを定義することを多重継承という。
それから、継承に関してだるまの考え(というより偏見?)を述べておきます(※1)。
継承はスーパークラスの属性と、操作(※基本的にはアクセスメソッドのみ)を引き継いだクラスを作るためのもの。
ただし、本当に継承が必要なのか(コンポジションでは駄目なのか)もう一度考えて欲しいです。
これは継承するしないに限らないのですが、データ構造(エンティティクラスの構成)の定義は慎重に行った方が良いです。
データ構造はその後のプログラムの保守性に大きく関係するためです。
絶対に差分プログラミングをするためのものではない。
差分プログラミングを考えるということは、処理中心で考えているということではないでしょうか?
POA(プロセス中心アプローチ。実は、プログラム中心アプローチとも言う)の欠点をもう一度見直して欲しいです。
処理はデータと比べて変更されやすいです。
変更されやすい処理中心で考えたクラスを引き継いで、そのクラスに本当に変更が加わったらどうするのでしょうか?
すべてのサブクラスを見直さないといけません。(すべてのサブクラスをテストし直さないといけません。)
スーパークラスは変更されにくいデータを中心に考えたクラスであるべきだと思います。
多態性を実現したかったら、継承ではなくインタフェースの実装で可能なので、それでやればいい(※2)。
というより、そうすべき。
多態性ってオブジェクトによってメソッドの動作が変わるっていうものだけど、「動作」という言葉が気になる。
これも、いつの間にかPOAで考えてないか?
継承にはいろいろ問題があるので、そういうところは継承ではなく、インタフェースの実装+委譲の方がいい(※3)と思います。
-----
※1:かなり、極端な表現なので、あまり鵜呑みにはしないでください。そのうち、修正するかもしれません。
※2:とはいうものの、実際には継承することを前提としてクラスが作成されていることがある(例えば、java.lang.Exception)ので、継承を使うしかない。しかし、このクラスはたぶん何人もの研究者がいろいろ調査(java以前の言語の例外機構など)・検討して作られたのだから、継承とするのが正しいのだろう。
※3:継承よりも、インタフェースの実装+コンポジションの方がクラス間の結合度が低くなるようです。
継承の注意としては以下のようなものがあるので、えーと、挙げておきます。
サブクラスを理解するのが面倒くさくなる。
サブクラスを作るときは楽だよ。
本当に。
なにせ、スーパークラスとの差分だけを作ればいいのだから。
で、それを後で、理解するとなった場合、両方見ないといけないんだけど…。
これは本に良く書いてあることだけど、継承のしすぎは良くない。
スーパークラスに変更がかかるとサブクラスすべてに変更がかかる。
つまり、スーパークラスに変更があったらすべてのサブクラスまでテストしないといけなくなる。
スーパークラスとサブクラス間の結合度が強くなる。
どうも、モジュール間の(スーパークラスとサブクラス間の)の結合度が強くなってしまうらしい(※1、2)。
Googleでいろいろ調べたけど、結合度が強くなると書いてあるページはあったものの、実際に何結合なのかが書いているページが見つからなかった…。
ごめん…。
せっかくこのページを見てくれたというのに…。
言語によってサポート状況が異なる。
VBAでは継承が使えない。
VBAのバージョンが6以上であれば、インタフェースのみの継承はできますが、Mac版エクセルVBAはVBAのバージョンが5だからなぁ。
他にも、C++は多重継承が可能ですが、Javaでは多重継承できない等があるので注意した方が良いです。
クラスは、サブクラスとしてではなく、スーパクラスとして使用される可能性があります。
当たり前のことだけど、サブクラスでメソッドをオーバライドする際、メソッドの意味が変わるようなオーバライドをしてはいけないです。
(いろんなページに書いてあることですが。)
また、メソッドを呼び出す際の前提条件を厳しくするのはあまりよくないです。
さらに、詳細なことは、「リスコフの置換原則 」でGoogleで調べてください。
継承を使用するなとは言いません。デザインパターンでも継承を使ってますし、JavaのAPIの中にだって継承を使ったものがたくさんあります。エクセルそのものも、継承を使用していると思われるクラスがあります。
ただ、継承を使用するときは注意して欲しいというだけです。
------
※1:ちなみに、オブジェクト指向において(いや、オブジェクト指向に限らずだけど)、モジュール間の結合度は弱い方が良いです
。
※2:Russ Miles (著), Kim Hamilton (著), 原 隆文 (翻訳) 入門
UML 2.0 ISBN 978-4873113173 の
「5.1.5.1
汎化と実装の再利用」(p87) にも継承を行うと親クラスの結合度が高くなると書かれています。
継承に関しての原則を名前だけ紹介しておきます。
リスコフの置換原則
詳しいことは自分で調べてください。(Googleなどで調べるか、リンクを参照してください。)
あ、そういえば、Javaのjava.util.Propertiesクラス って、リスコフの置換原則に違反していると思うのですがどうでしょうか?
なんで、java.util.HashTable を継承しているの?
普通に考えておかしいと思うが(java.util.HashTableのインスタンスをクラス内に1つもつようなクラス構成にするならわかる)。
(java.util.Propertiesクラスの説明のページに、言い訳のようなこと(HashTableの関数を使用するなということ)が書いてある)
このページを作成するのに参考にしたページです。
ただし、だるまは、このページを作成するにあたり、これらのページを100%理解してから作成したわけではない(おいおい。)です。
間違い(リンク先のページではなく、このページに)があったら、ごめんなさい。
番号
著者名
書籍名
ISBN
1
Russ Miles (著), Kim Hamilton (著), 原 隆文 (翻訳)
入門
UML 2.0
978-4873113173
このページの利用によって発生した、いかなる損害について、このホームページの作成者は責任を負いません。
このページの間違いや嘘を見つけた方、このページに書いて欲しい情報がある方は
メール をお願いします。
Microsoft 、Windows 、Visual Basic および Excel は米国Microsoft
Corporationの米国およびその他の国における登録商標または商標です。
ここではExcel® をエクセル、Visual Basic® for
Applications をVBAと表記する場合があります。
Mac 、Mac OS 、Mac OS X は米国Apple
Computer,Inc.の登録商標または商標です。
JavaおよびJavaに関する商標は、米国およびその他の国における米国Sun
Microsystems,
Inc.の商標または登録商標です。
その他、社名および商品名、システム名称などは、一般に各社の商標または登録商標です。
このホームページの作成者はこれらの会社とはいっさい関係がありません。