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

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

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

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

Q&A

解決済

5回答

1062閲覧

Java 引数によってクラスフィールドを変える処理について switch文

tinkai

総合スコア17

Java

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

0グッド

0クリップ

投稿2018/09/13 06:37

Javaのプログラミングについて質問です。
idによってクラスフィールドを変える方法を知りたいです。
現在は下記のプログラムのようにSwitch文を用いてフィールドの変更を行っています。
しかし、caseが20以上あることや、フィールドを変える際の処理の量などから、コード量が多くなっています。
これらを解決する方法はありますか?

まとめると、解決したい点は

  • クラスフィールドを引数(id)で変更する際の方法
  • 現在のコードよりも短く、わかりやすくなるか
  • その他、コードの改良点など(初心者なのでバンバン言って頂きたいです)

説明不足な点が多々あると思うので、気軽に質問してください。
よろしくお願いします。

lang

1public class A { 2 private int id; 3 private String name; 4 private int hoge; 5 private B b[]; 6 7 A(int id) { 8 this.id = id; 9 decideField(id); 10 } 11 12// hoge, bのコンストラクタの引数は、他のケースと同じ場合も違う場合もある。 13 private void decideField(id) { 14 switch (id) { 15 case 0: 16 this.name = "0"; 17 this.hoge = 0; 18 this.b = new b[2]; 19 this.b[0] = new B(0, "name"); 20 this.b[1] = new B(5, "name"); 21 return; 22 case 1: 23 this.name = "1"; 24 this.hoge = 1; 25 this.b = new b[3]; 26 this.b[0] = new B(3, "name"); 27 this.b[1] = new B(0, "name"); 28 this.b[2] = new B(2, "name"); 29 return; 30 case 2: 31 this.name = "2"; 32 this.hoge = 2; 33 this.b = new b[1]; 34 this.b[0] = new B(2, "name"); 35 return; 36 ... // caseが約20程度続く 37 ... 38 ... 39 default: 40 } 41 }

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

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

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

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

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

guest

回答5

0

ベストアンサー

BeatStarさんも指摘しているところですが、クラス抽出などを検討すると良いと思います。
このままというならこんな感じでしょうか、多少はすっきりするかもしれません。

Java

1class A { 2 public static enum Factory{ 3 ZERO(0, "0", 0, new B(0, "name"), new B(5, "name")), 4 ONE(1, "1", 1, new B(3, "name"), new B(0, "name"), new B(2, "name")), 5 TWO(2, "2", 2, new B(2, "name")), 6 /// ・・・ 7 ; 8 9 private Supplier<A> suplier; 10 11 private Factory(int id, String name, int hoge, B... b) { 12 suplier = () -> new A(id, name, hoge, b); 13 } 14 15 public static A create(int id) { 16 return Arrays.stream(Factory.values()) 17 .filter(p -> p.ordinal() == id) 18 .findFirst() 19 .orElseThrow(IllegalArgumentException::new) 20 .suplier.get(); 21 } 22 } 23 24 private int id; 25 private String name; 26 private int hoge; 27 private B b[]; 28 29 private A(int id, String name, int hoge, B[] b) { 30 this.id = id; 31 this.name = name; 32 this.hoge = hoge; 33 this.b = b; 34 } 35}

投稿2018/09/13 08:59

YamakawaJunichi

総合スコア630

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

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

swordone

2018/09/14 00:40

enumでなくてもMapとかのほうが選定処理がわかりやすいかと思う
YamakawaJunichi

2018/09/14 01:02

定数的な意味合いを重視したのと個人的な好みでenumにしました。 Mapもありですね。
tinkai

2018/09/14 01:31

回答ありがとうございます。 見たことない表現が何個もありますが、こちらの方が分かりやすいと思います。 supplierについて勉強してから検討してみたいと思います。
guest

0

YamakawaJunichiさんの回答を参考に、Mapを使って書いてみました。

java

1class A { 2 private static final Map<Integer, Supplier<A>> map; 3 static { 4 Map<Integer, Supplier<A>> tempMap = new HashMap<>(); 5 tempMap.put(0, () -> new A(0, "0", 0, new B(0, "name"), new B(5, "name"))); 6 tempMap.put(1, () -> new A(1, "1", 1, new B(3, "name"), new B(0, "name"), new B(2, "name"))); 7 tempMap.put(2, () -> new A(2, "2", 2, new B(2, "name"))); 8 ... 9 map = Collections.unmodifiableMap(tempMap); 10 } 11 12 private int id; 13 private String name; 14 private int hoge; 15 private B b[]; 16 17 public A(int id, String name, int hoge, B... b) { 18 this.id = id; 19 this.name = name; 20 this.hoge = hoge; 21 this.b = b; 22 } 23 24 public A(int id) { 25 this.id = id; 26 } 27 28 static A factory(int id) { 29 return map.getOrDefault(id, () -> new A(id)).get(); 30 } 31}

投稿2018/09/14 01:15

swordone

総合スコア20651

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

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

tinkai

2018/09/14 02:04

回答ありがとうございます。 自分の勉強不足で知らない表現がありますが、すっきりしていてわかりやすいと思います。 勉強してから検討してみたいと思います。
guest

0

オブジェクト指向の多様性の出番ではないでしょうか。とりあえず、以下のようにすれば switch はなくなります。(まったく検証してないのでコンパイルも通らないと思いますが雰囲気だけ)
それで、 A x = new A(1); と呼ぶかわりに A x = new A1(); とコンストラクトし、 x.getName() と呼ぶと x に多様性が出ます。

java

1public class A { 2 abstract public String getName(); 3 abstract public int getHoge(); 4 public B b[]; 5} 6 7public class A0 extends A { 8 public String getName() { 9 return "0"; 10 } 11 public int getHoge() { 12 return 0; 13 } 14 A0 () { 15 this.b = new b[2]; 16 this.b[0] = new B(0, "name"); 17 this.b[1] = new B(5, "name"); 18 } 19} 20 21public class A1 extends A { 22 public String getName() { 23 return "1"; 24 } 25 public int getHoge() { 26 return 1; 27 } 28 A1 () { 29 this.b = new b[3]; 30 this.b[0] = new B(3, "name"); 31 this.b[1] = new B(0, "name"); 32 this.b[2] = new B(2, "name"); 33 } 34} 35 36public class A2 extends A { 37 public String getName() { 38 return "2"; 39 } 40 public int getHoge() { 41 return 2; 42 } 43 A2 () { 44 this.b = new b[1]; 45 this.b[0] = new B(2, "name"); 46 } 47}

上記で変数bの宣言は A0, A1, A2 に共通のもので、親クラスに1回だけ宣言されていることに注意してください。
さらに A0, A1, A2 .. に共通する処理を親クラスで実装することによって、固有処理から共通処理を呼び出せたりします。

java

1public class A { 2 public void 共通処理() { 3 ... 4 } 5 abstract String 多様性(); 6} 7 8public class A0 { 9 public String 多様性() { 10 固有処理 11 ... 12 共通処理(); // Aの共通処理を呼び出す 13 固有処理 14 ... 15 } 16}

投稿2018/09/13 09:11

mit0223

総合スコア3401

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

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

tinkai

2018/09/14 01:51

回答ありがとうございます。 継承するということですね。 確かにクラスAは全部同じ処理をするからそういう考え方もできますね。 だけど、コード量やファイルが増えてしまうと思うのですが、それは仕方ないことなのでしょうか?
mit0223

2018/09/14 06:18

もし、サンプルコードの状況で終わりであれば、継承はコードが増えますが、複雑になってくれば、それほどは増えないはずです。通常は、共通コードがあり、それが階層化します。たとえば、一部のクラス間で共通のコードがあれば、それらをサブクラスでまとめてそのサブクラスに共通コードを書くことで、複雑な分岐を避けることができます。メソッドのオーバライドで分岐することで if 文と switch 文を減らすことで可読性を向上させることができます。
guest

0

私ならそのままか、どうしてもっていうなら条件次第ですがクラスを抽出します。

例えばC++で言うなら構造体みたいなクラス ( フィールドのみのクラス。get/setぐらいはあってもいいけど。 ) を抽出して、

デザインパターンでいうStateパターンだっけな。それみたいにしますね。

投稿2018/09/13 07:21

BeatStar

総合スコア4958

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

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

tinkai

2018/09/14 01:20

回答ありがとうございます。 まだまだプログラミング初心者なのであまり掴めませんが、デザインパターンというものがあるんですね。 勉強してみたいと思います。
guest

0

A のインスタンスを作るときのパラメータを
0 -> [0, "0", [[0, "name], [5, "name"]]]
1 -> [1, "1", [[3, "name], [0, "name], [2, "name]]]
2 -> [2, "2", [[2, "name]]]
のよう連想配列で保持し、
コンストラクタでは、id から得た連想配列の値に従って 初期化をしていくようにすればよいと思います。

ruby だと、上記のような連想配列の初期化宣言が簡単にできるのですが、
java では型宣言や 連想配列の初期化がちょっと面倒です。
でもひとまず java で書いてみました。
java に慣れた方ならもっとよい 書き方ができと思います。
クラス A に toString() を定義して、生成したインスタンスに内容を確認できるようにしています。
ここで、 new B(...) したものを連想配列には入れていません。
A を new する度に、B を new してそれを a のインスタンスに与えないといけないからです。

java

1package teratail; 2 3import java.util.HashMap; 4import java.util.Map; 5 6class Pair { 7 public int v; 8 public String s; 9 Pair(int v, String s) { 10 this.v = v; 11 this.s = s; 12 } 13} 14 15class B { 16 public int val; 17 public String name; 18 B(int val, String name) { 19 this.val = val; 20 this.name = name; 21 } 22} 23 24public class A { 25 private int id; 26 private String name; 27 private int hoge; 28 private B b[]; 29 30 final static Map<Integer, Object[]> PARAMS; 31 static { 32 final Pair PARAMS_0[] = { 33 new Pair(0, "0"), 34 new Pair(1, "1"), 35 new Pair(2, "2") 36 }; 37 final Pair PARAMS_B[][] = { 38 { new Pair(0, "name"), new Pair(2, "name") }, 39 { new Pair(3, "name"), new Pair(0, "name"), new Pair(2, "name")}, 40 { new Pair(2, "0") } 41 }; 42 43 PARAMS = new HashMap<>(); 44 Object[] pair0 = {PARAMS_0[0], PARAMS_B[0]}; 45 PARAMS.put(0, pair0); 46 Object[] pair1 = {PARAMS_0[1], PARAMS_B[1]}; 47 PARAMS.put(1, pair1); 48 Object[] pair2 = {PARAMS_0[2], PARAMS_B[2]}; 49 PARAMS.put(2, pair2); 50 } 51 52 A(int id) { 53 this.id = id; 54 decideField(id); 55 } 56 public String toString() { 57 String ans = "id:" + id; 58 ans += ", name:" + name + ", hoge:" + hoge; 59 ans += " B["; 60 for (B x : b) { 61 ans += "(" + x.val + ", " + x.name + ") "; 62 } 63 ans += "]"; 64 return ans; 65 } 66 67 private void decideField(int id) { 68 Object[] ps = PARAMS.get(id); 69 Pair params_0 = (Pair)(ps[0]); 70 Pair[] params_b = (Pair[])(ps[1]); 71 72 this.name = params_0.s; 73 this.hoge = params_0.v; 74 75 int len = params_b.length; 76 this.b = new B[params_b.length]; 77 for (int i = 0; i < len; i++) { 78 Pair p = params_b[i]; 79 this.b[i] = new B(p.v, p.s); 80 } 81 } 82 83 public static void main(String[] args) { 84 System.out.println(new A(0)); 85 System.out.println(new A(1)); 86 System.out.println(new A(2)); 87 } 88}

実行例
イメージ説明

投稿2018/09/15 13:10

katoy

総合スコア22324

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問