![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?8acaa2e)
ある機能Aを持ったクラスを作りたいとき、次の二つの方法があると思います。
(1) サブクラス
→ 機能Aを持ったクラスを拡張したサブクラスを作る。
(2) インターフェース
→ 機能Aを実現するメソッドをまとめてインターフェースにし、そのインターフェースを実装するクラスを作る。
これらの使い分けはどうすればよいのでしょうか?つまり、どういうときに(1)を使ってどういうときに(2)を使えばよいのでしょうか?
私が現在思いつく(1)と(2)の違いは以下の二つです。
・(1)の方法は手軽
・(1)の方法だと、一つのクラスの拡張しかできない
これくらいでしょうか。もっと本質的な違いはあるのでしょうか?
No.3ベストアンサー
- 回答日時:
基本はインタフェースです。
インタフェースがあれば、拡張によることはすべてできます。
extendsによる拡張は、Java言語に別に無くてもいいけれど、
プログラマの便利のために存在しているものです。
オブジェクト指向のえらい人ピーター・コードは、
継承を使うときの基準として以下のような条件を挙げています。(『Peter CoadによるJavaオブジェクト設計』)
(1)「何々の特別な種類」であって、「何々によって果たされる役割」ではない
(2)(継承を使ったときに得られるオブジェクトは)何か別のクラスのオブジェクトに変形する必要は生じない。
(3)スーパークラスを拡張するのであって、スーパークラスをオーバライドまたは無効化するのではない。
(4)ユーティリティクラス(プログラム上の便利のためのクラス)に過ぎないクラスをサブクラス化するのではない。
(5)PD(問題領域:実現しようとするシステムの中で本質的なもの)の中では、役割、トランザクションまたはデバイスの特別な種類を表す。
要するに、
「Aを拡張したBは、絶対にあくまでもAに属する一種類である」
と確定していない限り、継承は使うなということです。
機能だけを使いたいなら、継承でもインタフェースでもなく、
コンポジションというやり方もあります。(上記の参考文献参照)
ポリモーフィズムを使う必要がない場合は、
この方法が安全確実ではないかと思います。
参考URL:http://www.amazon.co.jp/exec/obidos/ASIN/4894710 …
この回答への補足
ありがとうございます!
これは良さそうな本ですね。購入しようと思います。
翻訳は読みやすいでしょうか?
読みにくければ原書を買おうと思います。
No.6
- 回答日時:
既に他の方がいろいろ書かれているので,私は少し別の視点から。
サブクラスとインターフェイスの違いは,実装の集中管理をするか否かにあるのではないかと思います。
サブクラスを利用している場合,親クラスのあるメソッドの実装が変更されたとすると,それは(子クラスでオーバーライドしていない)全ての子クラスのメソッドにも自動的に反映されます。
一方,これがインターフェイスの場合,親クラスの実装の変更は子クラスに及ばないので,もし同様に変更を反映させたい場合,全ての子クラスの実装を(コピペかなにかで)同様に変更してやる必要があります。
もちろんこれは良し悪しで,親クラスの実装の変更が自動的に子クラスに反映されることで,予期せぬ変更が生じて困る場合もあります。
以上から,個人的には,
・作り始めの段階ではサブクラスで継承を使って実装を一元管理する
・デバッグが進んで,それ以上実装が変更されることがほとんどないと考えられる状態になったら,インターフェイスに置き換える(ただし,他の方が書かれているように,サブクラスにする必然性のあるものまでインターフェイスに置き換える必要はありません)
というのがいいのではないかと思います。
#これはNo.2の方がいわれている方法とよく似ていますね。
この回答への補足
実践的なアドバイスをありがとうございます。
インターフェースが基本だ、と思いつつあったので、
>サブクラスにする必然性のあるものまで
>インターフェイスに置き換える必要はありません
これは勘違いしていました。
No.5
- 回答日時:
オブジェクト指向が流行りだした以前は、
「オブジェクト指向」といったら、「継承」というくらいよく聞かれたのですが、その弊害についても色々と議論され、近年では継承の危険性についてよく聞きます。
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、読んでみます。ありがとうございます。
No.4
- 回答日時:
>ということは、サブクラスで実現できるときはサブクラスで、ということでしょうか?
#3の方針がいいっすね。
私も、機能(クラス)の特殊化・機能拡張がサブクラスというようなことでいいと思います。
多重継承したくなるような時というのは、機能(クラス)が他にも欲しいときというような感じでいいんじゃないですか
No.2
- 回答日時:
これは深い問題であり、人それぞれの考えがあると思います。
以下は、私の経験で得た考えです。かなり異端だと思いますが、ご参考までに。インターフェースはそれ自体は状態(フィールド)を持たない代わりに、後からいくらでもどんなクラスにでも付け足すことができるものです。一方、クラスは状態を持つことができるのですが、後から付け足すことができないものです。
インターフェースは、十徳ナイフを作るのには便利で臨機応変が効きます。クラスはツブシが効かないですが、本来は状態と密に連携できるクラスで作ることを考えて作ったほうがキレイな設計になることが多いと感じます。ただ、動的な設計変更が起こり得るようなことを考慮すると、本当はクラスのほうがいいんだけど、インターフェースでもできるからインターフェースでやっちゃおうか、という考え方で割り切ったほうがいろいろとメリットが出てくるかもしれません。
したがって、設計は abstract class を基本にし、それを extends した (concrete な) class を作ることを念頭に置いて、しかしコーディング時はそれを interface に置き換えてしまうほうがいいのではないかと考えます。
この回答への補足
> 設計は abstract class を基本にし、それを
> extends した (concrete な) class を作ること
> を念頭に置いて、しかしコーディング時はそれを
> interface に置き換えてしまう
ありがとうございます。
ちょっと完全に理解できていないのですが、出来るだけインターフェースにしておいた方がよい、ということでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java javaのクラスの分け方について質問です。 APIの内部用と外部用でクラスを分けたいのですがインター 2 2022/04/26 16:06
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- ネットワーク プロトコルの階層化とインターフェースとの違い 2 2022/07/26 02:38
- Chrome(クローム) VMWareを使用して、ChromeOSをWindows11のPCに入れたい 1 2022/11/15 19:04
- Java javaの質問です 次の機能を有するメソッド4つを自クラスに作成し、実装したいです 【機能】 足し算 1 2022/06/15 15:14
- Java javaの質問です 次の機能を有するメソッド4つを自クラスに作成し、実装したいです 【機能】 足し算 1 2022/06/15 17:49
- その他(ブラウザ) Twitterの「返信をさらに表示」 ボタンの後ろに隠れているツイートを常に表示 1 2023/08/04 12:20
- Chrome(クローム) スマホはauのアンドロイドです。 GoogleChromeの拡張機能としてKeepaを使いたいです。 2 2023/04/08 20:08
- Java java 次の機能を有するメソッドを自クラスに作成し、実装したいです。 機能 名前判定機能 →名前が 3 2022/06/16 16:08
- その他(プログラミング・Web制作) Pythonで複数のメソッドをまとめて管理する方法について 1 2023/03/30 00:01
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「ラッパークラス」の存在意義...
-
JavaでのAPIの覚え方ってみさな...
-
(vba)他のアプリケーションの右...
-
デバッグ時に「Source not found」
-
単体テストのテストケースにて...
-
Javaでタスクシステムを作るの...
-
ファイルパスが取得出来ない(P...
-
抽象クラスのエラーが出ます
-
c++でのヘッダーファイルの循環...
-
オブジェクト指向のインターフ...
-
Vector、ArrayList、LinkedList...
-
WPF C# PointToClient
-
タイマーの作り方
-
委譲って何ですか?
-
Javaのインスタンス化の構文の...
-
c# この高速化の方法あり?
-
interface,extend,implementの...
-
「IOException は対応する try ...
-
javaでクッキー認証を必要とす...
-
オブジェクト指向の特徴
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
interface,extend,implementの...
-
C# 「データが失なわれる可能性...
-
「ラッパークラス」の存在意義...
-
c++でのヘッダーファイルの循環...
-
(vba)他のアプリケーションの右...
-
JavaでのAPIの覚え方ってみさな...
-
ゲッターを使わないで変数にア...
-
「継承されたメソッドの可視性...
-
「IOException は対応する try ...
-
【C#】クラスのコンストラクタ...
-
VB DLLプロジェクトについて
-
Javaのインスタンス化の構文の...
-
Javaで下線
-
委譲って何ですか?
-
ASP.NETでの共通コードの書き方...
-
オーバーライドとラッパーの違い
-
抽象クラスをJUNITでテストする...
-
JTextFieldの入力制限
-
Commons-Discovery.jarとは?
-
setTextについて
おすすめ情報