
![]() |
|||
|
世の中に存在するオブジェクトの多様性を効率的に表現するためには継承だけでは不完全です。そこで、インターフェイスと実装をクラス階層中の別の場所に配置する仕組みが必要になります。 |
|||
![]() |
|||
| このトピックでは次の用語を覚えます: | |||
|
|||
![]() |
|||
|
「犬」「猫」「猿」クラスは「動物」クラスを継承しているとします。すると例えば、「呼吸する」という機能は「犬」「猫」「猿」すべてに共通のものなので、「動物」クラスで定義されます。 それでは、「鳴く」という機能はどうでしょうか?「鳴く」という行為は「犬」「猫」「猿」どれも似ています。しかし、鳴き声は全く違います。「犬」クラスのインスタンスに「鳴け」と命令した場合(つまり「鳴く」メソッドを実行した場合)は「わん!」と鳴くでしょうし、「猫」クラスのインスタンスなら「にゃ!」と鳴くでしょう。そこで、それぞれのクラスについて、共通の目的と独自の挙動をもつメソッドを定義する必要があるわけです。このようなメソッドはクラス階層のどこで定義されるべきでしょうか? |
|||
|
|||
|
もっと深く観察しましょう。 「鳴く」というメソッドが「犬」「猫」「猿」どのクラスのインスタンスでも実行可能であるということは、このメソッドに関して、「犬」「猫」「猿」の各クラスが同じインターフェイスを持っているのだということです。一方、鳴き声が「犬」「猫」「猿」各クラスで異なるということは、「鳴く」メソッドの実装は共通ではないということです。 つまり、インターフェイスは「動物」クラスで定義し、実装は「犬」「猫」「猿」クラスで定義するのが自然です。 |
|||
|
インターフェイスが「動物」クラスで定義されると、そのサブクラスである「犬」「猫」「猿」クラスのインスタンスを扱うときに、それが実際にどのサブクラスに属するのかを知る必要がなくなります。それがどのクラスのインスタンスであろうと「動物」インスタンスの一種なので、「動物」クラスで定義されている「鳴く」メソッドを共通的に実行できるのです。そしてインスタンス自身は自分がどのクラスに属しているか知っているので、自分専用の実装を使用して鳴き声を出します。 |
|||||||
![]() |
|||||||
|
このように、インターフェイスがひとつでも、オブジェクトが属するクラスによって挙動が変わる仕組みのことをポリモーフィズムと言います(多態性・多様性・多相性などと訳される場合もあります)。ちなみに形容詞はポリモーフィックです。この仕組みが、実は、オブジェクト指向の要です。
|
|||||||
|
C++ や Java では、スーパークラスにデフォルトの動作を実装しておき、必要なときだけサブクラスで独自の実装をすることができます。例えば「食べる」というメソッドは「動物」クラスの多くのサブクラスで共通の実装を利用できますが、「アリジゴク」クラスは少し変わっています(アリジゴクは体液を吸い取るのです、ああ気持ち悪い)。そこで、「アリジゴク」クラスでは共通の実装をキャンセルして、独自の実装に切り替えることになります。このように、特定のサブクラスでだけ実装を書き換えることをオーバーライドと言います。オブジェクトを扱うときに、オーバーライドされているかどうかを気にする必要はありません。一度規格化されたインターフェイスは不変だからです。 |
|||
(「オブジェクト指向のはなし」は1999年2月から2000年4月にかけて作成されたコンテンツです。)