質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

抽象クラスはなぜ必要か?

解決済

回答 4

投稿

  • 評価
  • クリップ 5
  • VIEW 18K+

score 589

Javaプログラミングを勉強しています。

抽象クラスについて疑問を持ちました。

結論から言うと、
・抽象クラスって必要でしょうか?
・現場でそんなに使っているのでしょうか?

抽象クラスの特徴としては以下の認識です。
・インスタンス化できない。
・サブクラスに継承することを前提に作成される。
・抽象クラスで宣言された抽象メソッドは継承されたサブクラス側で必ずオーバーライドされなければならない。



その結果、メリットは以下の2点であると思われます。
・サブクラス定義時にメソッドに間違いがあればコンパイルエラーが起き、コーディングミスを避けられる。
・複数のクラスで共通の名前や呼び出し方をもつメソッドは抽象クラスで抽象メソッドとして宣言しておき、それをサブクラスで実装させるようにできる。


たしかにこの2点がメリットではあるけれど、現場でそんなに使っているのでしょうか?

共通で使うなら、具象クラスにメソッドを定義してそれを複数のクラスに継承する方がサブクラスのコード量も減って便利なのかなとおもいます。


現場で抽象クラスをよく使う方がいれば、その目的、使用方法、メリットをお伺いできればと思います。
また「現場ではあまり使わない」と言った生の声もお待ちしています。

もしアドバイス頂ける方がいればよろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+12

抽象クラスやインターフェースなどOOPで登場する概念は、コードの共通化ができたりコード量が減らせたりするなど「便利だから存在する」と言うよりは、構築していくシステムの『概念』をより正確に定義しコードを分かりやすくするための概念です。また、Javaの進化と共にアノテーションで共有する概念を宣言したり、DIコンテナ等で共通する処理を注入するなど、別の手段が取れるようになってきているため、抽象クラスが登場する場面は減ってきていると言えそうです。(例:JUnitのTestCaseが@Testになった、等)

質問者さまがあげられたメリットを根拠に抽象クラスを採用すると、後々ロジックが入り組むでしょう。

では、「どういう時に抽象クラスを採用するか」、というと、本当に減ってきていると思います。抽象クラスを採用すると、20年前に出版されたGoFによる「デザインパターン入門」にも「できるだけ継承より委譲を採用せよ」という趣旨が書かれているくらい、コードを書く時に継承は避けるべきです。親のクラスの性質をまるまる引き継ぐような概念はそう多くありません。子クラスは親クラスの性質をちゃんと引き継いでいるか確認する必要が出てくるので、テスタビリティが下がりますし。

よくトランザクションの開始、終了タイミングを揃えるよう、昔は抽象クラスを使い、テンプレートメソッドパターンにしていました。しかし、近年は同様の事を実現するためにアノテーションを使います。トランザクションが必要なメソッドにアノテーションを宣言すれば、後はフレームワークがいいようにします。

では、『抽象クラスでなければならないようなクラスはどんなクラスか』というと、例えばJavaFXのNodeクラスがあります。このクラスJavaFXのコンポーネントの基底クラスで、シーングラフを構成するためのクラスです。シーングラフとは、ウィンドウ(シーン)上にレイアウト用のパネルやボタンを載せていく機構です。ボタンにしろテキストフォームにしろ、どのコンポーネントもどの位置にどんなレイアウトで表示するのか、という情報は共通に必要です。そういう基底クラスを定義するときに抽象クラスを採用します。
JavaFXに馴染みがないのであれば、HTMLのタグも似たようなものです。どのタグにもスタイルだったりCSSのクラス名を定義できますが、aタグはリンクになるなど具象的な機能を持ちます。そういう概念を表す場合、HTMLTagという基底クラスを抽象クラスとして定義し、AnchorTagなどの具象クラスはHTMLTagを継承するように設計するでしょう。

抽象クラスはそういう基底クラスを設計する時に登場する概念です。何度も繰り返しますが、そんな風に性質を引き継がないといけないような概念はそう多くないので、システムを構築するような場合はあまり登場しないのではないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/15 17:36

    kompiroさん
    回答ありがとうございます。
    たしかに私も抽象クラスのメリットを根拠に抽象クラスを採用すると、あまりよくないんじゃないかなと思っていました。他によりいい方法があったり、ロジックが入り組んだりといったデメリットが考えられたからです。

    そうなんですね。やはり概念的な部分が大きく、また日進月歩進化するプログラミング業界ではより良い手段が増えてきているため、使用する機会はどんどん減ってきているんですね。

    そんな気はしていましたが、実際の生の意見を聞けて説得力が増しました。そのようなお話が聞けてよかったです。

    わかりやすく、丁寧で、私の求めている回答を頂くことができました。
    もちろん他のお二方も同様です。

    感謝しています。ありがとうございました。

    キャンセル

+3

現場でJavaを使ったことがないので教科書的なところだけ

Javaで使われる抽象クラス、インターフェースでの抽象メソッドはあるクラスが継承、実装したら必ずその機能が存在するということを保証するためにあります。
下のようなクラスだと、一つのメソッドの実装を継承で使い回すことはできません。
ガソリンを補給するのと充電するのとでは処理の内容が大幅に異なるからです。

抽象クラスにインスタンスが代入できたのだったら燃料補給ってやれば実際の処理は違っていても、燃料が補給されているということが期待できます。

abstract class 車{
    int 速度;
    //普通のメソッド
    void 加速(int 速度増分){
        速度 += 速度増分;
    }
    //抽象メソッド
    abstract void 燃料補給(int 補給量);
}

class 電気自動車 extends 車{
    int 電池残量;
    void 燃料補給(int 補給量){
        電池残量 += 補給量;
    }
}

class ガソリン車 extends 車{
    int ガソリン残量;
    void 燃料補給(int 補給量){
        ガソリン残量 += 補給量;
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/15 16:14

    ShotaKurodaさん
    回答ありがとうございます。

    なるほど。
    ・実装したら機能が存在することの保証。(オーバーライドしないといけないという特徴を活かした)
    ・処理内容をもたない抽象メソッドだからこそサブクラスの処理の複雑さに対応できる。
    といったことですね。

    2点目は具象クラスにはできない内容なので感心しました。

    たしかにこれだと抽象クラスだからこそって感じですね。

    新しい視点を学ぶことができました。ありがとうございます。感謝しています。

    キャンセル

+1

はじめまして。
java歴は浅いですが回答します。
自社開発の現場ではあまり使いませんが、似たような計算、処理を繰り返すことが事前に分かっている時にあえて作成することがあります。
また、それなりの規模の案件で外部の人間が入ってくる場合に間違えを減らす為作成することもあります。
私はソースコードが増えてしまうという理由で、ほとんど使用しませんが、エラー箇所を減らすという意味では使用した方が無難かと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/15 15:48 編集

    kpiyohikoさん
    回答ありがとうございます。
    なるほど。やはり大規模プロジェクトや新参者が入ってくる場合は、メリットの2つが効いてくるんですね。

    実際の具体的な使用頻度が気になるところではありますが、これは自分が肌で感じないとわからない部分かもしれませんね。

    迅速な対応ありがとうございました。

    キャンセル

  • 2015/09/15 15:55

    使用頻度ですが、会社や現場、規模に寄るとしかいえません;;
    私が関わった中規模~大規模案件ではリーダーによって多用するチームとほとんど使わないチームとに分かれていました。
    進捗の具合はやはり多用している方が出戻りが少ないので、優位でした。
    ただ、ほぼすべてのタスクを把握している通称妖怪リーダーのチームはほとんど抽象クラスをほとんど使用していないのに出戻りが皆無でした…

    ここには私よりはるかに様々な経験をしている方がたくさんいらっしゃるので私も実際はどうなのか気になります!

    キャンセル

  • 2015/09/15 16:03

    わざわざ追加回答ありがとうございます!

    そうなんですね。
    確かにこればっかりはリーダーの気質にも寄ると思います。もちろプロジェクトの規模感や特徴も。

    その感覚は自分で実際に体験してみないとハッキリとはしないものかもしれません。

    とはいえ私もいろいろな意見は聞きたいのでもう少し他の方の意見も待ってみます。

    ありがとうございます!

    キャンセル

+1

私もJava歴はあまりありませんが、先日シリアル通信アプリを少々作ってみました。
通信の方は専用のクラスを作り、メインはGUIで表現することにしました。
そこで、通信の受信イベントで受け取った情報をGUI側に反映させるにはどうしたらよいのか悩みました。
その時初めてabstractクラスとそのメソッドを実装しました。

この方法があっているのかわかりませんが、通信クラスをabstractクラスにして、受信イベントの処理の部分にabstractメソッドを呼び出すようにしました。
その実装をメインのGUIクラスの方ですることにより、GUIの方に受け取った値を中継することができました。

/** 通信側のクラス */
public class 通信クラス implements 通信リスナー {
    @Override
    public void 受信イベント(Event event) {
        受信処理(受信データ);
   }
   public abstract void 受信処理(String 受信データ);
}

/** GUI側のクラス */
public class GUIクラス extends 通信クラス {
    private テキストボックス テキスト;
   // 略 
 通信クラス() {
        テキストボックス テキスト = new テキストボックス();
    }
    @Override
    public void 受信処理( String 受信データ ) {
        テキスト.setText(受信データ);
    }
    // 略
}
コード

使い方があっているかどうかはわかりませんが、思い通りの動きをしました。
内容を抽象化するために日本語でクラス名やメソッド名を書いてみました。
具体的にはrxtxライブラリを用いたシリアル通信アプリですが、標準ライブラリにはない(ネット上には置かれています)ものですので、あえてこのように抽象化した記述をしてみました。

別にインターフェースで実装してもよいのでしょうが、今回は実装方法も決めていましたので、extends と implementsを同時に呼ぶ必要もないと考えたので今回はこのようにしました。
通信だけできる(継承されれば)クラスと描画もできるように拡張したクラスの継承関係ですね。

インターフェースは表面の繋がりを持たせるものなので、内部と外部をつなぐということでしょうか。
abstractクラスやインターフェースは概念が難しいですが使えば面白いこともできそうです。

では。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る