抽象クラスからオーバーライドについて

このQ&Aのポイント
  • Javaの抽象クラスを継承してオーバーライドする方法について質問があります。
  • 質問内容は、抽象クラスで「面積を計算する」というメソッドを定義し、そのメソッドを継承して「四角形の面積を計算する」というメソッドと「三角形の面積を計算する」というメソッドを定義するというものです。
  • 質問者は、このプログラムを実行するために、1つのファイルに3つのクラス定義とmain関数を書く方法と、3つのファイルにクラス定義とmain関数を書く方法の2つを試しています。どちらがJavaらしいプログラムであるか質問しています。
回答を見る
  • ベストアンサー

抽象クラスからオーバーライドについて

EclipseでJavaを勉強始めました。 抽象クラスからオーバーライドするところで質問致します。 抽象クラスとして、「面積を計算する」というメソッドをもつDiagramクラスを定義しました。それを継承して、「四角形の面積を計算する」というメソッドをもつSquareクラスと、「三角形の面積を計算する」というメソッドをもつTriangleクラスを定義しました。 Squareクラス、Triangleクラスからインスタンスを生成して、四角形、三角形の面積をコンソールに表示させるという簡単なプログラムです。 このとき、main関数と3つのクラスの関係についてお尋ねします。 (1)iagram.java、Square.java、Triangle.javaそれぞれにクラス定義とmain関数を持たせるパターン public abstract class Diagram { // 面積計算定義(抽象メソッド) public static void main(String[] args) { } } public class Square extends Diagram{ //四角形の面積の計算定義 public static void main(String[] args) { //四角形の面積の計算と表示 } public class Triangle extends Diagram{ //三角形の面積の計算定義 public static void main(String[] args) { //三角形の面積の計算と表示 } (2)sample.javaというファイルにまとめ、その中にこの3つのクラス定義とmain関数を一つ持たせるパターン public class sample { public static void main(String[] args) { //四角形の面積の計算と表示 //三角形の面積の計算と表示 } } abstract class Diagram { // 面積計算(抽象メソッド)定義 } class Square extends Diagram{ //四角形の面積の計算定義 } class Trapezoid extends Diagram{ //三角形の面積の計算定義 } この二通りを考えて、どちらも実行できたのですが、どちらの方がJavaらしいプログラムと思われますでしょうか?

  • Java
  • 回答数7
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • HarukaV49
  • ベストアンサー率53% (48/89)
回答No.6

そもそも、オブジェクト指向設計の目的は、  <1>作成したクラスに再利用性がある(を持たせる)  <2>将来の仕様変更に対して最小限の修正で済む 事を第一の目的にしています。 (1)は明らかに問題があります。 例えば(1)も場合に、値をファイル出力するとなったらどうでしょうか? 面積を計算している部分の含まれたソースコードを触らなければ いけなくなっています。 面積の計算と出力は全く関係ありませんので、ソース上くっついていては 殆ど再利用性が無いと言う事になってしまっています。 (また、mainメソッドをオーバーライドするのも非常に不自然です) (2)では、1つのファイルにまとめてしまってはいけません。 なぜなら、Squareクラスに関するJavaDocが独立して存在しませんので、 sampleクラスを見るまでその存在に気付けません。 ということは、再利用性が閉ざされているということです。 なお、本例のような場合には、Diagramはインターフェースの方が良いです。 ちょうど、java.awt.Shapeインターフェースに対して、java.awt.Polygonや Line2D具象クラスが存在するのと同じ関係にするということです。 簡単に具体例を示してみると、 -- Diagram.java --- interface Diagram {  double solveArea(); // 面積を計算する  double solvePeriphery(); // 外周を計算する } -- Square.java --- public Square implements Diagram {  private ... // 四角形のパラメータ  public Square( ... ) {   ...  }  public double solveArea() {   // 四角形の面積の具体的な計算   return area;  }  public double solvePeriphery() {   // 四角形の外周の具体的な計算   return length;  } } -- Trapezoid.java --- public Trapezoid implements Diagram {  private ... // 三角形のパラメータ  public Trapezoid( ... ) {   ...  }  public double solveArea() {   // 三角形の面積の具体的な計算   return area;  }  public double solvePeriphery() {   // 三角形の外周の具体的な計算   return length;  } } そして、これを実行するメインメソッドを持つクラスを作ります。 public class Sample {  public static void main(String[] args) {   Diagram diagram = new Square( ... );   double ans = diagram.solveArea();   System.out.println( ans );  } } ここでは、四角形の面積を求めましたが、これを三角形の面積を 求めるように変更したいならば、mainメソッド内の1行目の右辺を  new Trapezoid( ... ); に書き換えれば済むわけです。 ここで、左辺をDiagramインターフェースで受けているのも重要で、 図形に関する処理が抽象化されるので汎用性が増しています。 同様に、面積から外周を求めるように変更したいならば、2行目だけを solvePeriphery() 書き換えれば済みます。

maiko100
質問者

補足

ご丁寧に有難う御座いました。改めて検討してみました。 ご指摘のとおり、 「面積計算」をインターフェースとして扱い、パッケージの中に (1)Diagram.javaにDiagramインターフェース (2)Square.javaにSquareクラス (3)Trapezoid.javaにTrapezoid クラス そして、 (4)Sample.javaにSampleクラス、ここにmainメソッドを書く という方法、とてもよく理解できました!。 一方「面積計算」を抽象クラス(メソッドのみ持つ)として扱い、パッケージの中に (1)はDiagram.javaにDiagram 抽象クラス (2)Square.javaにSquareクラス(Diagram 抽象クラスを継承) (3)Trapezoid.javaにTrapezoid クラス(Diagram 抽象クラスを継承) そして、 (4)Sample.javaにSampleクラス、ここにmainメソッドを書く という方法でも試してみましたが、 やはり、“「面積計算」をインターフェース”として扱うほうが、Javaらしいプログラムという理解でよろしいでしょうか?

その他の回答 (6)

  • HarukaV49
  • ベストアンサー率53% (48/89)
回答No.7

>一方「面積計算」を抽象クラス(メソッドのみ持つ)として扱い、パッケージの中に >・・・ >やはり、“「面積計算」をインターフェース”として扱うほうが、 >Javaらしいプログラムという理解でよろしいでしょうか? すばらしい探究心ですね! 誰をも説得できる最強の理由は、『Effective Java』に (項目16)抽象クラスよりインターフェースを選ぶ と、書いてあるからです。 きっと、今後も将来的にプログラミングを続けていかれるでしょうから、 ぜひ、当該書籍を入手されることをお勧めします。 『Effrctive Java プログラミング言語ガイド』 http://www.amazon.co.jp/Effective-Java-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E%E3%82%AC%E3%82%A4%E3%83%89-Joshua-Bloch/dp/4894714361/ref=pd_sim_b_1/249-6620391-0296315 実用上は、Squareクラスは、Shapeインターフェースも実装する必要があるでしょう。  public class Square implements Diagram, Shape {   ...  } 要するに、ひとつの理由はJavaはクラスの多重継承が認められていないので、 インターフェースを持たない抽象クラスを書いてしまうと実用上問題が 出てくるということです。 (よく見かけるこの様な表現ですが、正確には、Javaは言語仕様として、  インタフェースを使った実装を推奨するために、クラスの多重継承を  禁止しているという方が正しいでしょう) 蛇足ですが、  データ構造,デザインパターン,UML 等の言葉をキーワードに書籍を入手されれば、より専門的な分野の 知識が身に付くかと思います。 Effective Javaの内容も決して平易ではないので、その内容を理解するために 別の書籍を購入するというのもとても良い方法だと思います。

maiko100
質問者

補足

>ひとつの理由はJavaはクラスの多重継承が認められていないので、 VBだけかと思いましたが、Javaもそうだったんですね。 >インターフェースを持たない抽象クラスを書いてしまうと実用上問題が出てくるということです。 納得のいく説明ありがとうございます。

回答No.5

(2)の方がシンプルでいいですよね。 1ファイルに1publicクラスでなくていけない理由 http://q.hatena.ne.jp/1122966784 だるまのエクセルVBA トップ > オブジェクト指向についていろいろ > オブジェクト指向とモジュールの凝集度、モジュールの結合度 http://members3.jcom.home.ne.jp/daruma_kyo/aboutooa/module_cohesion_coupling.html ちなみに、リンク張っといておいて何ですが、下の方はざ~っと眺めておくだけでいいです。とにかく、以下の2点を覚えておいてください。 良いクラス→ ・結合度が弱い ・凝縮度が高い

  • harutovx
  • ベストアンサー率50% (11/22)
回答No.4

勉強のためにやるなら(1)でも良いと思うけど、 私が、実際に作る場合は(2)で作ります。 表示までclassに持たせるのは、ちょっとどうかと思いますね。

maiko100
質問者

お礼

表示までclassに持たせるのは、確かにおっしゃるとおりでした・・・・

  • ANASTASIAK
  • ベストアンサー率19% (658/3306)
回答No.3

そのような定型処理なら、ルーチン化すべきでしょう。 なので、(2)

maiko100
質問者

お礼

ありがとうございます。(2)かなと思いますが。

  • dyna_1550
  • ベストアンサー率34% (122/353)
回答No.2

機能継承になるので、個人的な意見としてはどちらもJavaらしくないと思います。 「面積」って抽象的ですか?

maiko100
質問者

お礼

ありがとうございます。テキストの例題が、「面積」⇒三角形、四角形の面積とあったものですから

  • PED02744
  • ベストアンサー率40% (157/390)
回答No.1

どちらかを選べといわれれば(2)かな? と思いますが、JAVAの基本は1クラス1ファイルなので、私なら全部クラス毎にファイルをわけるかなあ・・・と思います。 特に抽象クラスやインタフェースは、定義のみで実装は外部に任せるというイメージなので、少なくとも抽象クラスやインタフェースは別ファイルにすべきだと思われます。 まぁ、この程度のソースなら1つのファイルでも良いのでしょうが。

maiko100
質問者

お礼

ありがとうございます。VBはかじったのですが、JAVAはよくわからなくて。 >全部クラス毎にファイルをわけるかなあ・ をもう少し教えていただければ幸いです。

関連するQ&A

  • 「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」

    「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」は正しい? はじめまして。Javaのインタフェースに関する質問です。 私はこれまで、インタフェースを使うときは、インタフェースを実装してクラスを宣言し、そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する、と理解していました。 しかし、下の例をみてください。抽象メソッドの定義を、インタフェースの実装の以前で与えています。問題無くコンパイルでき、実行できます。実行結果も以下の通りです。 インタフェースの抽象メソッドへの定義の与え方やその実行のされ方は、メソッドのオーバーライドと同様と思っていましたので、下記のコードでは「クラスBが抽象クラスではありません」や、「インタフェースの抽象メソッドがオーバーライドされていません」などの文法エラーがでると思っていました。 そこで、質問です。 インタフェースが持つ抽象メソッドの定義を与える場所について、または、これに関する説明のあるページなど、何かご存知でしたら教えてください。 ★コード★ interface X{   void show(); } class A{   public void show(){     System.out.println("A");   } } class B extends A implements X{ } public class Main{   public static void main(String[] args){     X x=new B();     x.show();   } } ★実行結果★ >java Main A ★Java環境★ java 1.6.0_21 javac 1.6.0_16

    • ベストアンサー
    • Java
  • あれ?

    すいません。 長い間、 疑問に思ってたことがあるんですけれども、 (1) import javax.swing.*; class Sample {  public static void main (String args[])  {   ........   Aメソッド()  } } (2) import javax.swing.*; class Sample extends aiueo {   public static void main (String args[])  {   ........   Aメソッド()  } } (3) class Sample extends aiueo {  public static void main (String args[])  {    ........   Aメソッド()  } } の違いが、 考えれば考えるほどわからなくなってきました。 パッケージと継承の関係について、 どうやら理解できていないみたいです。 どなたか分かりやすく教えてください。 よろしくお願いします。 (注) Aメソッドはaiueoクラスのメソッドとし、 aiueoクラスはjavax.swingパッケージに入っているものとします。

    • ベストアンサー
    • Java
  • 抽象クラス について

    obj.write();した時 class super1 の write()が呼ばれ その後 class HINA の write()が呼ばるのか? 直接 class HINA の write()が呼ばるのか? どう呼び出してるのか 教えてください abstract class super1 { abstract void write(); } class HINA extends super1{ void write() { System.out.println( "LOVE HINA" ); } } class test { public static void main( String args[] ) { super1 obj = new HINA(); obj.write(); } } }

  • オーバーライドの必要性

    まだまだJavaを勉強している途中なのですが、下記のサンプルコードでオーバーライド(メソッドをオーバーロードすることをオーバーライドというのでしょうか…!?)のの必要性がよく分からなくなってしまったので質問させて頂きました。 /* sample.java */ abstract class super_class{  void write(){} } class CLASS1 extends super_class{  void write(){ System.out.println("CLASS1"); } } class CLASS2 extends super_class{  void write(){ System.out.println("CLASS2"); } } class sample{  public static void main(String args[]){   super_class obj = new CLASS2();   obj.write();   obj = new CLASS1();   obj.write();  } } 以上のコードを実行した場合 CLASS2 CLASS1 と表示されるのは多少なりとも勉強して分かったつもりでした…。 しかし、あくまでサンプルであるために特に意味がないことでもオーバーライドの説明をしているのだろうという風に考えてしまったのですが、 結局は、 スーパークラスとサブクラスに同じシグネチャのメソッドがあった場合、各サブクラスのメソッドが実行される と言うことは、スーパークラスのwrite()メソッドは何をしているのでしょうか? 多様性はJavaでも大切なものであるとのことなので質問させて頂きました。 なるべくわかりやすく説明して頂きたいと思います。 どうかお答えをお願いします。

    • ベストアンサー
    • Java
  • メソッドのオーバーライド(java)

    class A3{ void hello(){ System.out.println("A3"); } void hello(int i){ System.out.println("A3"+i); } } class B3 extends A3{ void hello(){ System.out.println("B3"); } } class C3 extends B3{ void hello(String s){ System.out.println("C3"+s); } } class MethodOverriding3{ public static void main(String args[]){ A3 obj = new C3(); obj.hello(); } } 上のプログラムを実行すると"B3"と表示されまが、どうしてクラスBのメソッドが実行されるのでしょうか? クラスAのメソッドが無視される仕組みがわかりません。 また、クラスMethodOverriding3でobj.hello("abc")としてコンパイルすると mo.java:25: シンボルを見つけられません。 シンボル: メソッド hello(java.lang.String) 場所 : A3 の クラス obj.hello("abc");   ^ エラー 1 個 とエラーが出ます。 どうしてでしょうか? 誰か教えてください、お願いします。

    • ベストアンサー
    • Java
  • 違いを教えてください。

    JAVA初心者です。勉強しててわからない事がたくさん・・・ まず、public static void main(String args[])と    public static void main(String []args) は同じ意味なのでしょうか?そもそも(String args[])の意味がよくわかりません・・・。argsってなんて読んだらいいのでしょうか? あと、extends継承してクラスを使うのと、importでクラスを使うのって意味は同じですか? 最後に、abstract抽象も使い方がよくわかりません。 教えてください!!

    • ベストアンサー
    • Java
  • クラスについての質問です!!

    本に下のような説明があったのですが、ここで出てくる「メンバ」という言葉がわかりません。 これはどういう意味合いなのでしょうか? よろしくお願いします。 ――――――――――――――――――――――――――― public class JsMsg1{ public static void main (String args[ ]) { ・・・ } } というプログラムはJsMsgというクラスがあり、メンバとしてmain()メソッドがあり、フィールドはないというクラス構成をしています。

    • ベストアンサー
    • Java
  • 親クラスから子クラスへアクセス。

    親クラスから子クラスへアクセス。 お世話になります。 以下のプログラムについて考えています。 public class Main{  public static void main(String[] args) {   SubA subA = new SubA();   SubB subB = new SubB();   Super[] subs = {subA,subB};   subs[1].method();   subs[2].method();  } } class Super{  String str = "親";  public void method(){   System.out.println(str);  } } class SubA extends Super{  String str = "子A"; } class SubB extends Super{  String str = "子B"; } この場合、出力結果は当然 親 親 になります。 これを子クラスの str を表示するようにしたいのです。つまり 子A 子B です。 ただし、子クラスで method() をオーバーライドしたり、super.str = "子A" のように親クラスを書きかえずにです。 子クラスが何百種類もある場合、全く同じmethod()を書く無駄や、変更があったときにそれを全てを修正しなければならないことを避けたいのです。 何か良案がありましたら、ぜひご教授ください。よろしくお願いします。

  • mainクラスのpublicの意味を教えて下さい

     お早う御座います、JAVA初心者です、宜しくお願いします。  main クラスの public をコメントアウトしてもエラーもなく走ります。  これは、「public static void main(String[] args)」を持っているクラスを自動的に「main クラス」と判断しているということでしょうか。 ============================================================ class Sub { void disp() { System.out.println(" a "); } } /*public*/ class Main { public static void main(String[] args) { Sub s = new Sub(); s.disp(); } }

    • ベストアンサー
    • Java
  • java 実行できない

    javaで public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello World!"); } } のようなプログラムをかいて、コンパイルして、実行しようとすると エラー: メイン・メソッドがクラスStringで見つかりません。次のようにメイン・メソッドを定義してください。 public static void main(String[] args) またはJavaFXアプリケーション・クラスはjavafx.application.Applicationを拡張する必要がありま というエラーがでます。コンパイルはできます。jdkは1.8.0_25を使っています。

専門家に質問してみよう