電子書籍の厳選無料作品が豊富!

ある機能Aを持ったクラスを作りたいとき、次の二つの方法があると思います。

(1) サブクラス

→ 機能Aを持ったクラスを拡張したサブクラスを作る。

(2) インターフェース

→ 機能Aを実現するメソッドをまとめてインターフェースにし、そのインターフェースを実装するクラスを作る。

これらの使い分けはどうすればよいのでしょうか?つまり、どういうときに(1)を使ってどういうときに(2)を使えばよいのでしょうか?


私が現在思いつく(1)と(2)の違いは以下の二つです。

・(1)の方法は手軽
・(1)の方法だと、一つのクラスの拡張しかできない

これくらいでしょうか。もっと本質的な違いはあるのでしょうか?

A 回答 (6件)

基本はインタフェースです。


インタフェースがあれば、拡張によることはすべてできます。
extendsによる拡張は、Java言語に別に無くてもいいけれど、
プログラマの便利のために存在しているものです。

オブジェクト指向のえらい人ピーター・コードは、
継承を使うときの基準として以下のような条件を挙げています。(『Peter CoadによるJavaオブジェクト設計』)

(1)「何々の特別な種類」であって、「何々によって果たされる役割」ではない

(2)(継承を使ったときに得られるオブジェクトは)何か別のクラスのオブジェクトに変形する必要は生じない。

(3)スーパークラスを拡張するのであって、スーパークラスをオーバライドまたは無効化するのではない。

(4)ユーティリティクラス(プログラム上の便利のためのクラス)に過ぎないクラスをサブクラス化するのではない。

(5)PD(問題領域:実現しようとするシステムの中で本質的なもの)の中では、役割、トランザクションまたはデバイスの特別な種類を表す。

要するに、
「Aを拡張したBは、絶対にあくまでもAに属する一種類である」
と確定していない限り、継承は使うなということです。

機能だけを使いたいなら、継承でもインタフェースでもなく、
コンポジションというやり方もあります。(上記の参考文献参照)
ポリモーフィズムを使う必要がない場合は、
この方法が安全確実ではないかと思います。

参考URL:http://www.amazon.co.jp/exec/obidos/ASIN/4894710 …

この回答への補足

ありがとうございます!
これは良さそうな本ですね。購入しようと思います。

翻訳は読みやすいでしょうか?
読みにくければ原書を買おうと思います。

補足日時:2005/04/03 21:50
    • good
    • 0

既に他の方がいろいろ書かれているので,私は少し別の視点から。



サブクラスとインターフェイスの違いは,実装の集中管理をするか否かにあるのではないかと思います。

サブクラスを利用している場合,親クラスのあるメソッドの実装が変更されたとすると,それは(子クラスでオーバーライドしていない)全ての子クラスのメソッドにも自動的に反映されます。

一方,これがインターフェイスの場合,親クラスの実装の変更は子クラスに及ばないので,もし同様に変更を反映させたい場合,全ての子クラスの実装を(コピペかなにかで)同様に変更してやる必要があります。

もちろんこれは良し悪しで,親クラスの実装の変更が自動的に子クラスに反映されることで,予期せぬ変更が生じて困る場合もあります。

以上から,個人的には,

・作り始めの段階ではサブクラスで継承を使って実装を一元管理する
・デバッグが進んで,それ以上実装が変更されることがほとんどないと考えられる状態になったら,インターフェイスに置き換える(ただし,他の方が書かれているように,サブクラスにする必然性のあるものまでインターフェイスに置き換える必要はありません)

というのがいいのではないかと思います。

#これはNo.2の方がいわれている方法とよく似ていますね。

この回答への補足

実践的なアドバイスをありがとうございます。

インターフェースが基本だ、と思いつつあったので、

>サブクラスにする必然性のあるものまで
>インターフェイスに置き換える必要はありません

これは勘違いしていました。

補足日時:2005/04/06 10:21
    • good
    • 0

オブジェクト指向が流行りだした以前は、


「オブジェクト指向」といったら、「継承」というくらいよく聞かれたのですが、その弊害についても色々と議論され、近年では継承の危険性についてよく聞きます。
http://www.pc-view.net/Solution/040120/page14.html

No.3の方のおっしゃるように、インターフェースでできないかをまず検討すべきだと思います。
継承する(サブクラスを作る)にしても、よく検討しないと危険なので、むやみやたらに使うべきではないということです。

Effective Javaは誰もが認める良書だと思います。

第四章 クラスとインターフェース
 14 継承よりもコンポジションを選ぶ
 15 継承のために設計および文書化する、でなければ継承を禁止する
 16 抽象クラスよりインターフェースを選ぶ

参考URL:http://www.amazon.co.jp/exec/obidos/ASIN/4894714 …

この回答への補足

私は C++ 出身なのですが、たしかに、継承で悩むことが非常に多かったです。

Effective Java、読んでみます。ありがとうございます。

補足日時:2005/04/06 10:23
    • good
    • 0

>ということは、サブクラスで実現できるときはサブクラスで、ということでしょうか?


#3の方針がいいっすね。

私も、機能(クラス)の特殊化・機能拡張がサブクラスというようなことでいいと思います。
多重継承したくなるような時というのは、機能(クラス)が他にも欲しいときというような感じでいいんじゃないですか
    • good
    • 0

これは深い問題であり、人それぞれの考えがあると思います。

以下は、私の経験で得た考えです。かなり異端だと思いますが、ご参考までに。

インターフェースはそれ自体は状態(フィールド)を持たない代わりに、後からいくらでもどんなクラスにでも付け足すことができるものです。一方、クラスは状態を持つことができるのですが、後から付け足すことができないものです。
インターフェースは、十徳ナイフを作るのには便利で臨機応変が効きます。クラスはツブシが効かないですが、本来は状態と密に連携できるクラスで作ることを考えて作ったほうがキレイな設計になることが多いと感じます。ただ、動的な設計変更が起こり得るようなことを考慮すると、本当はクラスのほうがいいんだけど、インターフェースでもできるからインターフェースでやっちゃおうか、という考え方で割り切ったほうがいろいろとメリットが出てくるかもしれません。
したがって、設計は abstract class を基本にし、それを extends した (concrete な) class を作ることを念頭に置いて、しかしコーディング時はそれを interface に置き換えてしまうほうがいいのではないかと考えます。

この回答への補足

> 設計は abstract class を基本にし、それを
> extends した (concrete な) class を作ること
> を念頭に置いて、しかしコーディング時はそれを
> interface に置き換えてしまう

ありがとうございます。
ちょっと完全に理解できていないのですが、出来るだけインターフェースにしておいた方がよい、ということでしょうか?

補足日時:2005/04/03 21:15
    • good
    • 0

ありきたりの回答ですが、


サブクラスによって実現できないような場合(多重継承みたいな感じになる時)インターフェースを使うというのでどうでしょう

この回答への補足

ということは、サブクラスで実現できるときはサブクラスで、ということでしょうか?

補足日時:2005/04/03 21:15
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!