回答編集履歴

8

Pokemonのコンストラクタを private 化

2023/03/15 17:54

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -62,7 +62,7 @@
62
62
  final String name;
63
63
  private Action[] actions = new Action[3];
64
64
 
65
- Pokemon(String name) {
65
+ private Pokemon(String name) {
66
66
  this.name = name;
67
67
  }
68
68
  @Override

7

サンプルコード

2023/03/15 17:50

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -8,6 +8,130 @@
8
8
 
9
9
  ---
10
10
 
11
+ >「Species」に151種の列挙定数を、「Move」に165種の列挙定数を、「Type」に15種
12
+
13
+ ということですが、上で書いたのと同じく私なら Species と Move は enum にはしません。 Type は enum が妥当と考えます。
14
+ ポケモンを P(p)okemon, 技を A(a)ction としてやってみると以下な感じ。
15
+
16
+ pokemon.csv
17
+ ```csv
18
+ ポケモン1, たいあたり, みずでっぽう, null
19
+ ポケモン2, たいあたり, ひのこ, なきごえ
20
+ ```
21
+ action.csv
22
+ ```csv
23
+ たいあたり, NORMAL, PHYSICAL, 50, 30, THREE
24
+ みずでっぽう, WATER, SPECIAL, 10, 10, THREE
25
+ ひのこ, FIRE, SPECIAL, 20, 20, THREE
26
+ つるのむち, GRASS, SPECIAL, 30, 30, THREE
27
+ なきごえ, NORMAL, STATUS, 40, 40, THREE
28
+ ```
29
+ Pokemon.java
30
+ ```java
31
+ import java.io.*;
32
+ import java.util.HashMap;
33
+ import java.util.Map;
34
+
35
+ public class Pokemon {
36
+ public static void main(String[] args) throws IOException {
37
+ Map<String,Action> actionMap = Action.readCsv("action.csv");
38
+ Map<String,Pokemon> map = Pokemon.readCsv("pokemon.csv", actionMap);
39
+ for(Pokemon p : map.values()) System.out.println("pokemon="+p);
40
+ }
41
+
42
+ private static Map<String,Pokemon> readCsv(String filename, Map<String,Action> actionMap) throws IOException {
43
+ Map<String,Pokemon> map = new HashMap<>();
44
+ try(BufferedReader r = new BufferedReader(new FileReader(filename))) {
45
+ for(String line; (line=r.readLine()) != null; ) {
46
+ String[] tokens = line.split(", *");
47
+ if(tokens.length != 4) throw new IOException("format error: line="+line);
48
+ if(map.containsKey(tokens[0])) throw new IOException("overloaded: line="+line);
49
+ Pokemon p = new Pokemon(tokens[0]);
50
+ map.put(tokens[0], p);
51
+ for(int i=0; i<3; i++) {
52
+ if(tokens[1+i].equals("null")) continue;
53
+ Action action = actionMap.get(tokens[1+i]);
54
+ if(action == null) throw new IOException("action not found: line="+line);
55
+ p.actions[i] = action;
56
+ }
57
+ }
58
+ }
59
+ return map;
60
+ }
61
+
62
+ final String name;
63
+ private Action[] actions = new Action[3];
64
+
65
+ Pokemon(String name) {
66
+ this.name = name;
67
+ }
68
+ @Override
69
+ public String toString(){
70
+ return super.toString()+"["+name+","+actions[0]+","+actions[1]+","+actions[2]+"]";
71
+ }
72
+ }
73
+
74
+ enum Type {
75
+ NORMAL, WATER, FIRE, GRASS
76
+ }
77
+ enum Category {
78
+ PHYSICAL, SPECIAL, STATUS
79
+ }
80
+ enum Priority {
81
+ ONE, TWO, THREE
82
+ }
83
+
84
+ class Action {
85
+ static Map<String,Action> readCsv(String filename) throws IOException {
86
+ Map<String,Action> map = new HashMap<>();
87
+ try(BufferedReader r = new BufferedReader(new FileReader(filename))) {
88
+ for(String line; (line=r.readLine()) != null; ) {
89
+ String[] tokens = line.split(", *");
90
+ if(tokens.length != 6) throw new IOException("format error: line="+line);
91
+ if(map.containsKey(tokens[0])) throw new IOException("overloaded: line="+line);
92
+ try {
93
+ map.put(tokens[0], new Action(tokens[0],
94
+ Type.valueOf(tokens[1]),
95
+ Category.valueOf(tokens[2]),
96
+ Integer.parseInt(tokens[3]),
97
+ Integer.parseInt(tokens[4]),
98
+ Priority.valueOf(tokens[5])));
99
+ } catch(IllegalArgumentException e) {
100
+ throw new IOException("format error: line="+line, e);
101
+ }
102
+ }
103
+ }
104
+ return map;
105
+ }
106
+
107
+ final String name; // 名
108
+ final Type type; // タイプ
109
+ final Category category; // 型(ぶつり/とくしゅ/へんか)
110
+ final int power; // 威力
111
+ final int pp; // 使用最大回数
112
+ final Priority priority; // 優先度
113
+
114
+ private Action(String name, Type type, Category category, int power, int pp, Priority priority) {
115
+ this.name = name;
116
+ this.type = type;
117
+ this.category = category;
118
+ this.power = power;
119
+ this.pp = pp;
120
+ this.priority = priority;
121
+ }
122
+
123
+ @Override
124
+ public String toString(){
125
+ return super.toString()+"["+name+","+type+","+category+","+power+","+pp+","+priority+"]";
126
+ }
127
+ }
128
+ ```
129
+ 実行
130
+ ```
131
+ pokemon=Pokemon@85ede7b[ポケモン1,Action@5674cd4d[たいあたり,NORMAL,PHYSICAL,50,30,THREE],Action@63961c42[みずでっぽう,WATER,SPECIAL,10,10,THREE],null]
132
+ pokemon=Pokemon@65b54208[ポケモン2,Action@5674cd4d[たいあたり,NORMAL,PHYSICAL,50,30,THREE],Action@1be6f5c3[ひのこ,FIRE,SPECIAL,20,20,THREE],Action@6b884d57[なきごえ,NORMAL,STATUS,40,40,THREE]]
133
+ ```
134
+
11
135
  enum は端的にはメソッド呼び出しで範囲のあるパラメータの指定間違いをコンパイルエラーで取り易くするというだけです。
12
136
  プログラムが扱う(ファイル等から取得する)データの値の範囲をコンパイルエラーとして取り除くことは出来ません。
13
137
  結局プログラムを動作させなければ分からないことですので、上に書いたようにファイルの読み込み時にそれぞれの値をチェックするというのは enum でも普通の class でも同じですし、普通のオブジェクトに保存した値を変更できなくすれば読み込んだ後に不正値になる心配もありません。

6

追加

2023/03/15 16:47

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -5,3 +5,9 @@
5
5
  なお、 enum (の定義自体)が沢山あるのと enum のメンバ(オブジェクト)が沢山あるのは違いますので、表現はご注意された方が良いと思います。
6
6
 
7
7
  csv 等から enum を import する場合は getById メソッドのようなもので enum に戻すことになるので、そこで不正値なら例外を発すれば、基本的な型の安全は保てます。(null を返すのは発見が遅れるので好ましくないと考えます。)
8
+
9
+ ---
10
+
11
+ enum は端的にはメソッド呼び出しで範囲のあるパラメータの指定間違いをコンパイルエラーで取り易くするというだけです。
12
+ プログラムが扱う(ファイル等から取得する)データの値の範囲をコンパイルエラーとして取り除くことは出来ません。
13
+ 結局プログラムを動作させなければ分からないことですので、上に書いたようにファイルの読み込み時にそれぞれの値をチェックするというのは enum でも普通の class でも同じですし、普通のオブジェクトに保存した値を変更できなくすれば読み込んだ後に不正値になる心配もありません。

5

追加修正

2023/03/15 02:40

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -1,7 +1,7 @@
1
1
  何個でも、必要なら作れば良いのでは無いでしょうか。
2
- 問題があるかどうかは環境に依る部分が大きいと思いますので、やってみれば分かることでしょう
3
- 私なら、型やタイプ(ポケモンやらないので違いが分かりません)はともかく、 Move 自体は enum にはしないで csv から読んでの普通のクラス/オブジェクトにするでしょう。
2
+ 問題があるかどうかは環境に依る部分が大きいと思いますので、やってみれば分かることで
3
+ でも私なら、型やタイプ(ポケモンやらないので違いが分かりません)はともかく、 Move 自体は enum にはしないで csv から読んでの普通のクラス/オブジェクトにするでしょう。技が何百種類あろうがある瞬間に同時に必要なのは幾つかだけなら、その都度オブジェクトを生成・削除すれば資源は最小限で済むはずです。そして今すぐそこまでの機能が必要な訳では無さそうですので、技オブジェクトの取得部分を取り替えられるようにしておいて、今は適当に返すようにします。
4
4
 
5
5
  なお、 enum (の定義自体)が沢山あるのと enum のメンバ(オブジェクト)が沢山あるのは違いますので、表現はご注意された方が良いと思います。
6
6
 
7
- csv 等から enum を inport する場合は getById メソッドのようなもので enum に戻すことになるので、そこで不正値なら例外を発すれば、基本的な型の安全は保てるでしょう。(null を返すのは発見が遅れるので好ましくないと考えます。)
7
+ csv 等から enum を import する場合は getById メソッドのようなもので enum に戻すことになるので、そこで不正値なら例外を発すれば、基本的な型の安全は保てます。(null を返すのは発見が遅れるので好ましくないと考えます。)

4

修正

2023/03/14 17:16

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -4,4 +4,4 @@
4
4
 
5
5
  なお、 enum (の定義自体)が沢山あるのと enum のメンバ(オブジェクト)が沢山あるのは違いますので、表現はご注意された方が良いと思います。
6
6
 
7
- csv 等 export した enum 当然 getById メソッドのようなもので enum に戻すことになるので、そこで不正値なら例外を発すれば、基本的な型の安全は保てるでしょう。(null を返すのは発見が遅れるので好ましくないと考えます。)
7
+ csv 等から enum を inport する場合は getById メソッドのようなもので enum に戻すことになるので、そこで不正値なら例外を発すれば、基本的な型の安全は保てるでしょう。(null を返すのは発見が遅れるので好ましくないと考えます。)

3

修正

2023/03/14 17:13

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -3,3 +3,5 @@
3
3
  私なら、型やタイプ(ポケモンやらないので違いが分かりません)はともかく、 Move 自体は enum にはしないで csv から読んでの普通のクラス/オブジェクトにするでしょう。
4
4
 
5
5
  なお、 enum (の定義自体)が沢山あるのと enum のメンバ(オブジェクト)が沢山あるのは違いますので、表現はご注意された方が良いと思います。
6
+
7
+ csv 等に export した enum は当然 getById メソッドのようなもので enum に戻すことになるので、そこで不正値なら例外を発すれば、基本的な型の安全は保てるでしょう。(null を返すのは発見が遅れるので好ましくないと考えます。)

2

修正

2023/03/14 17:08

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -1,5 +1,5 @@
1
1
  何個でも、必要なら作れば良いのでは無いでしょうか。
2
2
  問題があるかどうかは環境に依る部分が大きいと思いますので、やってみれば分かることでしょう。
3
- enum (の定義)が沢山あるのと enum のメンバ(オブジェクト)が沢山あのは違いますの、表現はご注意された方が良いと思います
3
+ 型やタイプ(ポケモンやらないで違いが分かりません)もかく、 Move 自体は enum にはしないで csv から読んで普通のクラス/オブジェクトにするでしょう
4
4
 
5
- みに、 enum の保持すデータは変更しないでしょうから、フィールドを private にして getter で読むでは無く、 フィールドを public(もしくはパッケープライベート) final にしてしえば getter 必要ありせん
5
+ 、 enum (定義自体)が沢山あのと enumメンバ(オブェクト)が沢山あるのは違いすので、表現ご注意された方が良いと思い

1

修正

2023/03/14 17:02

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -1,4 +1,5 @@
1
1
  何個でも、必要なら作れば良いのでは無いでしょうか。
2
2
  問題があるかどうかは環境に依る部分が大きいと思いますので、やってみれば分かることでしょう。
3
+ なお、 enum (の定義)が沢山あるのと enum のメンバ(オブジェクト)が沢山あるのは違いますので、表現はご注意された方が良いと思います。
3
4
 
4
5
  ちなみに、 enum の保持するデータは変更しないでしょうから、フィールドを private にして getter で読むのでは無く、 フィールドを public(もしくはパッケージプライベート) final にしてしまえば getter は必要ありません。