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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

Q&A

解決済

1回答

813閲覧

引数によって異なるサブクラスのインスタンスを返したい

fsk5303

総合スコア21

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

0グッド

0クリップ

投稿2019/08/29 08:16

編集2019/08/29 08:18

前提

  • 引数によって異なるサブクラスのインスタンスを返したい
  • もしくはその他の方法で下記要件を満たしたい
  • より良いクラス設計を学びたい

該当のソースコード

  • 下記のようなXMLを入力とします。
  • XMLのスキーマはname, detailまでは共通ですが、detailより下の階層はnameの中身によって変わります。
  • 実際に実現したいプログラムで使用するXMLのスキーマはもっと複雑ですが例として簡単にしています。

  • XML例1

xml

1<sports> 2 <name> 3 baseball 4 </name> 5 <detail> 6 <items> 7 <item> 8 ball 9 </item> 10 <item> 11 bat 12 </item> 13 <item> 14 glove 15 </item> 16 </items> 17 <swing> 18 double play.... 19 </swing> 20 </detail> 21</sports>
  • XML例2

xml

1<sports> 2 <name> 3 soccer 4 </name> 5 <detail> 6 <positions> 7 <position> 8 offence 9 </position> 10 <position> 11 diffence 12 </position> 13 <position> 14 midfielder 15 </position> 16 </positions> 17 <shoot> 18 goal!!! 19 </shoot> 20 </detail> 21</sports>

  • 各XMLの共通部分をスーパークラスとして定義しています。
  • 各XML独自の部分をサブクラスとして定義しています。
  • XML文字列を解析するXMLUtilクラスは省略しています。

  • Sportクラス

java

1public class Sport { 2 protected String name; 3 public Sport(String xml) { 4 // baseball / soccer 5 name = XmlUtil.get(xml, "name"); 6 } 7 public String getName() { 8 return name; 9 } 10} 11
  • Baseballクラス

java

1public class Baseball extends Sport { 2 private List<String> itemList; 3 private String swingResult; 4 public Baseball(String xml) { 5 super(xml); 6 7 // [ball, bat, glove] 8 itemList = XmlUtil.getList(xml, "items"); 9 // "double play..." 10 swingResult = XMlUtil.get(xml, "swing"); 11 } 12 public List<String >getItemList() { 13 return itemList; 14 } 15 public void swing() { 16 System.out.println(swingResult); 17 } 18}
  • Soccerクラス

java

1public class Soccer extends Sport { 2 private List<String> positionList; 3 private String shootResult; 4 public Soccer(String xml) { 5 super(xml); 6 7 // [offence, diffence, midfielder] 8 positionList = XmlUtil.getList(xml, "positions"); 9 // "goal!!!" 10 shootResult = XMlUtil.get(xml, "shoot"); 11 } 12 public List<String >getPositionList() { 13 return positionList; 14 } 15 public void shoot() { 16 System.out.println(shootResult); 17 } 18}

  • 呼び出し元クラスではXMLの中身に応じたサブクラスのインスタンスを生成し、それぞれ独自のメソッドを呼び出したいです。
  • このクラスではXmlUtilクラスのメソッドは呼び出したくないです。
  • 下記方法だと、new Sport(xml);new Baseball(xml);で二回スーパークラスのコンストラクタが呼び出されていると思います。そのため、とても冗長に感じています。

  • 呼び出し元クラス

java

1public void playSport(String xml) { 2 3 Sport sport = new Sport(xml); 4 5 if("baseball".equals(sport.getName())) { 6 Baseball baseball = new Baseball (xml); 7 baseball.swing(); 8 } else if ("soccer".equals(sport.getName())) { 9 Soccer soccer = new Soccer(xml); 10 soccer.shoot(); 11 } 12 13}

実現したいこと

  • 以下のようなイメージで一度でサブクラスを作成し処理を行うことはできないでしょうか?
  • このクラスではXML文字列の中身を解析したくはないです。

java

1public void newPlaySport(String xml) { 2 3 Sport sport = new Sport(xml); 4 5 if(sport instanceof Baseball) { 6 Baseball baseball = (Baseball)sport; 7 baseball.swing(); 8 } else if (sport instanceof Soccer) { 9 Soccer soccer = (Soccer)sport; 10 soccer.shoot(); 11 } 12 13}

ジェネリクスや抽象クラス等を組み合わせてやるとよいのか、あるいはファクトリクラスのようなものを定義するのがよいのか、いろいろ考えてみたのですが難しいです。
なにか、もっとこうした方がよい、私ならこうする、というようなアドバイスいただけると幸いです。
XMLのスキーマの設計等は変更はできません。

よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

Java 1.8

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以下のようなイメージで一度でサブクラスを作成し処理を行うことはできないでしょうか?

Javaの場合、new ClassNameと書いたものは本当にそのクラスしか作成できません。なので、Factory Methodを使う必要があります。

Sport Sport.fromXML(String xml)のようなメソッドを立てて、その内部でxmlを見て実際に作るクラスを作り分ければ、外部からはまとめて使えます。

投稿2019/08/29 08:21

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fsk5303

2019/08/29 08:37

早速のご回答ありがとうございます。やはりそのようなメソッドを作成する必要があるのですね。 少し追加で聞かせていただきたいのですが、 ・ファクトリメソッドを使う場合、Sportクラスに定義するのが好ましいですか?それともSportFactoryのような別のクラスを作成するのが好ましいですか? ・`Sport Sport.fromXML(String xml)`として実際にはサブクラスである`Baseball`や`Soccer`クラスのインスタンスを返しても問題ないのでしょうか?その場合、呼び出し元では返り値を`instanceof`で判定して分岐させるのが好ましいという認識であっているでしょうか?
maisumakun

2019/08/29 08:41

> ・ファクトリメソッドを使う場合、Sportクラスに定義するのが好ましいですか?それともSportFactoryのような別のクラスを作成するのが好ましいですか? このあたりは他の場所との兼ね合いにもよりますので、一概には言えないです。 > ・`Sport Sport.fromXML(String xml)`として実際にはサブクラスである`Baseball`や`Soccer`クラスのインスタンスを返しても問題ないのでしょうか? それを行えるようにするための仕組みがFactory Methodです。 > その場合、呼び出し元では返り値を`instanceof`で判定して分岐させるのが好ましいという認識であっているでしょうか? 実際のクラスを見て処理を分けるというのもあまり行儀が良くない感じはあります。play()のような抽象メソッドをSportにもたせて、どちらか気にせずに呼び出す、というような手法のほうがいいかもしれません。
fsk5303

2019/08/29 09:01 編集

ありがとうございます。play()のような共通のメソッドで処理を分ける方法は行いたいのですが、XMLのスキーマの特性上難しいです。 ファクトリクラスを以下のように定義しようと思います。 soccerやbaseballをEnum化したり、soccer,baseball以外だった場合の例外処理は検討の余地があるとおもいますが、その他で何かアドバイスありますでしょうか。 public class SportFactory { public static Sport createSport(String xml) { String sportName = XmlUtil.get(xml, "name"); if("baseball".equals(sportName)) { return new Baseball(xml); } else if ("soccer".equals(sportName)) { return new Soccer(xml); } return null; } }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問