teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

追記

2016/04/06 04:40

投稿

root_jp
root_jp

スコア4666

answer CHANGED
@@ -67,7 +67,7 @@
67
67
  ```
68
68
 
69
69
  ---
70
- ###**追記**
70
+ ###**追記**
71
71
  > MemberクラスのmemberRankプロパティに、各会員の状態を持たせる場合、どのような実装があり得ますか?
72
72
 
73
73
  問題はこれです。
@@ -171,3 +171,128 @@
171
171
  // rank は、1, 2, 3 の数値
172
172
  member.setMemberRank(MemberRank.of(rank));
173
173
  ```
174
+
175
+ ###**追記2**
176
+ > getPriceのようなメソッドを他にもいくつか追加したい場合、どういったクラス構成が望ましいですか?
177
+
178
+ 会員ランク毎に必要な振る舞いであれば、MemberRankで全て実装すべきです。
179
+ 例えば以下は、購入金額から付与されるポイントを計算するメソッドと
180
+ 特別会員かどうかを判断するメソッドを追加してみました。
181
+ これは、特別会員だけが見れる項目や、特別会員専用ページなどの制御で使うことを想定しています。
182
+
183
+ ```java
184
+ /**
185
+ * 会員ランクを表す列挙
186
+ */
187
+ enum MemberRank {
188
+
189
+ /** 一般会員 */
190
+ GENERAL(1) {
191
+ @Override
192
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
193
+ // 一般会員は定価のまま
194
+ return catalogPrice;
195
+ }
196
+
197
+ @Override
198
+ public BigDecimal getPoint(BigDecimal totalPrice) {
199
+ // 一般会員は購入金額の1%をポイント付与
200
+ BigDecimal percentage = new BigDecimal("0.01");
201
+ return totalPrice.multiply(percentage).setScale(0, BigDecimal.ROUND_DOWN);
202
+ }
203
+
204
+ @Override
205
+ public boolean isSpecialMember() {
206
+ // 一般会員は特別会員でない
207
+ return false;
208
+ }
209
+ },
210
+
211
+ /** シルバー会員 */
212
+ SILVER(2) {
213
+ @Override
214
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
215
+ // 5%引き
216
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.05"));
217
+ return catalogPrice.subtract(discountPrice);
218
+ }
219
+
220
+ @Override
221
+ public BigDecimal getPoint(BigDecimal totalPrice) {
222
+ // シルバー会員は購入金額の2%をポイント付与
223
+ BigDecimal percentage = new BigDecimal("0.02");
224
+ return totalPrice.multiply(percentage).setScale(0, BigDecimal.ROUND_DOWN);
225
+ }
226
+
227
+ @Override
228
+ public boolean isSpecialMember() {
229
+ // シルバー会員は特別会員でない
230
+ return false;
231
+ }
232
+ },
233
+
234
+ /** ゴールド会員 */
235
+ GOLD(3) {
236
+ @Override
237
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
238
+ // 10%引き
239
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.1"));
240
+ return catalogPrice.subtract(discountPrice);
241
+ }
242
+
243
+ @Override
244
+ public BigDecimal getPoint(BigDecimal totalPrice) {
245
+ // ゴールド会員は購入金額の3%をポイント付与
246
+ BigDecimal percentage = new BigDecimal("0.03");
247
+ return totalPrice.multiply(percentage).setScale(0, BigDecimal.ROUND_DOWN);
248
+ }
249
+
250
+ @Override
251
+ public boolean isSpecialMember() {
252
+ // ゴールド会員は特別会員
253
+ return true;
254
+ }
255
+ };
256
+
257
+ /**
258
+ * @param catalogPrice 定価
259
+ * @return ランクに応じた金額
260
+ */
261
+ public abstract BigDecimal getPrice(BigDecimal catalogPrice);
262
+
263
+ /**
264
+ * @param totalPrice 購入合計金額
265
+ * @return ランクに応じたポイント数
266
+ */
267
+ public abstract BigDecimal getPoint(BigDecimal totalPrice);
268
+
269
+ /**
270
+ * 特別会員かどうかを返す。
271
+ * <pre>
272
+ * 特別会員とはゴールド会員以上の会員のこと。
273
+ * (現状、ゴールド会員が最高ランクだが、来年にはプラチナ会員を導入予定)
274
+ * </pre>
275
+ *
276
+ * @return true..特別会員
277
+ */
278
+ public abstract boolean isSpecialMember();
279
+
280
+ /** 各列挙が持つ値 */
281
+ private int value;
282
+
283
+ /**
284
+ * コンストラクタ
285
+ */
286
+ private MemberRank(int value) {
287
+ this.value = value;
288
+ }
289
+
290
+ /**
291
+ * ファクトリー
292
+ */
293
+ public static MemberRank of(int value) {
294
+ return Stream.of(MemberRank.values()).filter(r -> r.value == value)
295
+ .findFirst().orElseThrow(IllegalArgumentException::new);
296
+ }
297
+ }
298
+ ```

1

追記

2016/04/06 04:40

投稿

root_jp
root_jp

スコア4666

answer CHANGED
@@ -64,4 +64,110 @@
64
64
  ```Java
65
65
  // getMember はセッションなどからログイン中の会員情報を取得するものとする
66
66
  BigDecimal price = getMember().getMemberRank().getPrice(catalogPrice);
67
- ```
67
+ ```
68
+
69
+ ---
70
+ ###**追記**
71
+ > MemberクラスのmemberRankプロパティに、各会員の状態を持たせる場合、どのような実装があり得ますか?
72
+
73
+ 問題はこれです。
74
+ 通常よくあるのは、データベースの会員情報から MemberRank を作成したいわけですから、
75
+ O/Rマッパーが Member取得時に自動で入れてくれたりもします。
76
+ データベースの値を MemberRank Enum に変換してくれます。
77
+
78
+ そういうのを省いて考えた場合どうなるかというと
79
+ 例えば、以下のような感じだと台無しなわけです。
80
+ ```java
81
+ if (rank.equals("general")) {
82
+ member.setMemberRank(MemberRank.GENERAL);
83
+ } else if (rank.equals("silver")) {
84
+ member.setMemberRank(MemberRank.SILVER);
85
+ } else if (rank.equals("gold")) {
86
+ member.setMemberRank(MemberRank.GOLD);
87
+ }
88
+ ```
89
+
90
+ こういった場合は、MemberRank に以下のようなファクトリーメソッドを用意するといいです。
91
+ ```java
92
+ public static MemberRank of(String name) {
93
+ return MemberRank.valueOf(name.toUpperCase());
94
+ }
95
+ ```
96
+
97
+ そうすると、以下のように設定できます。
98
+ ```java
99
+ // rank は、"general", "silver", "gold" の文字列
100
+ member.setMemberRank(MemberRank.of(rank));
101
+ ```
102
+
103
+ データに "general" などの文字列ではなく、
104
+ 一般会員 = 1, シルバー会員 = 2, ゴールド会員 = 3 などのように
105
+ 数値として持ちたいという事も多いでしょう。
106
+ その時は、MemberRankを以下のようにします。
107
+
108
+ ```java
109
+ /**
110
+ * 会員ランクを表す列挙
111
+ */
112
+ enum MemberRank {
113
+
114
+ /** 一般会員 */
115
+ GENERAL(1) {
116
+ @Override
117
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
118
+ // 一般会員は定価のまま
119
+ return catalogPrice;
120
+ }
121
+ },
122
+
123
+ /** シルバー会員 */
124
+ SILVER(2) {
125
+ @Override
126
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
127
+ // 5%引き
128
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.05"));
129
+ return catalogPrice.subtract(discountPrice);
130
+ }
131
+ },
132
+
133
+ /** ゴールド会員 */
134
+ GOLD(3) {
135
+ @Override
136
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
137
+ // 10%引き
138
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.1"));
139
+ return catalogPrice.subtract(discountPrice);
140
+ }
141
+ };
142
+
143
+ /** 各列挙が持つ値 */
144
+ private int value;
145
+
146
+ /**
147
+ * コンストラクタ
148
+ */
149
+ private MemberRank(int value) {
150
+ this.value = value;
151
+ }
152
+
153
+ /**
154
+ * @param catalogPrice 定価
155
+ * @return ランクに応じた金額
156
+ */
157
+ public abstract BigDecimal getPrice(BigDecimal catalogPrice);
158
+
159
+ /**
160
+ * ファクトリー
161
+ */
162
+ public static MemberRank of(int value) {
163
+ return Stream.of(MemberRank.values()).filter(r -> r.value == value)
164
+ .findFirst().orElseThrow(IllegalArgumentException::new);
165
+ }
166
+ }
167
+ ```
168
+
169
+ そうすると、以下のように設定できます。
170
+ ```java
171
+ // rank は、1, 2, 3 の数値
172
+ member.setMemberRank(MemberRank.of(rank));
173
+ ```