プロが教えるわが家の防犯対策術!

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らしいプログラムと思われますでしょうか?

A 回答 (7件)

そもそも、オブジェクト指向設計の目的は、


 <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() 書き換えれば済みます。

この回答への補足

ご丁寧に有難う御座いました。改めて検討してみました。
ご指摘のとおり、
「面積計算」をインターフェースとして扱い、パッケージの中に
(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らしいプログラムという理解でよろしいでしょうか?

補足日時:2007/07/13 15:26
    • good
    • 0

>一方「面積計算」を抽象クラス(メソッドのみ持つ)として扱い、パッケージの中に


>・・・
>やはり、“「面積計算」をインターフェース”として扱うほうが、
>Javaらしいプログラムという理解でよろしいでしょうか?

すばらしい探究心ですね!
誰をも説得できる最強の理由は、『Effective Java』に
(項目16)抽象クラスよりインターフェースを選ぶ
と、書いてあるからです。
きっと、今後も将来的にプログラミングを続けていかれるでしょうから、
ぜひ、当該書籍を入手されることをお勧めします。
『Effrctive Java プログラミング言語ガイド』
http://www.amazon.co.jp/Effective-Java-%E3%83%97 …


実用上は、Squareクラスは、Shapeインターフェースも実装する必要があるでしょう。
 public class Square implements Diagram, Shape {
  ...
 }
要するに、ひとつの理由はJavaはクラスの多重継承が認められていないので、
インターフェースを持たない抽象クラスを書いてしまうと実用上問題が
出てくるということです。
(よく見かけるこの様な表現ですが、正確には、Javaは言語仕様として、
 インタフェースを使った実装を推奨するために、クラスの多重継承を
 禁止しているという方が正しいでしょう)


蛇足ですが、
 データ構造,デザインパターン,UML
等の言葉をキーワードに書籍を入手されれば、より専門的な分野の
知識が身に付くかと思います。
Effective Javaの内容も決して平易ではないので、その内容を理解するために
別の書籍を購入するというのもとても良い方法だと思います。

この回答への補足

>ひとつの理由はJavaはクラスの多重継承が認められていないので、
VBだけかと思いましたが、Javaもそうだったんですね。

>インターフェースを持たない抽象クラスを書いてしまうと実用上問題が出てくるということです。
納得のいく説明ありがとうございます。

補足日時:2007/07/13 21:31
    • good
    • 0

(2)の方がシンプルでいいですよね。



1ファイルに1publicクラスでなくていけない理由
http://q.hatena.ne.jp/1122966784

だるまのエクセルVBA トップ > オブジェクト指向についていろいろ > オブジェクト指向とモジュールの凝集度、モジュールの結合度
http://members3.jcom.home.ne.jp/daruma_kyo/about …


ちなみに、リンク張っといておいて何ですが、下の方はざ~っと眺めておくだけでいいです。とにかく、以下の2点を覚えておいてください。

良いクラス→
・結合度が弱い
・凝縮度が高い
    • good
    • 0

勉強のためにやるなら(1)でも良いと思うけど、


私が、実際に作る場合は(2)で作ります。

表示までclassに持たせるのは、ちょっとどうかと思いますね。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/07/12 22:47

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


なので、(2)
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/07/12 22:46

機能継承になるので、個人的な意見としてはどちらもJavaらしくないと思います。


「面積」って抽象的ですか?
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/07/12 22:45

どちらかを選べといわれれば(2)かな?


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

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

お礼日時:2007/07/12 22:44

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