回答編集履歴

2

追記

2016/04/06 04:40

投稿

root_jp
root_jp

スコア4666

test CHANGED
@@ -136,7 +136,7 @@
136
136
 
137
137
  ---
138
138
 
139
- ###**追記**
139
+ ###**追記**
140
140
 
141
141
  > MemberクラスのmemberRankプロパティに、各会員の状態を持たせる場合、どのような実装があり得ますか?
142
142
 
@@ -345,3 +345,251 @@
345
345
  ```
346
346
 
347
347
 
348
+
349
+ ###**追記2**
350
+
351
+ > getPriceのようなメソッドを他にもいくつか追加したい場合、どういったクラス構成が望ましいですか?
352
+
353
+
354
+
355
+ 会員ランク毎に必要な振る舞いであれば、MemberRankで全て実装すべきです。
356
+
357
+ 例えば以下は、購入金額から付与されるポイントを計算するメソッドと
358
+
359
+ 特別会員かどうかを判断するメソッドを追加してみました。
360
+
361
+ これは、特別会員だけが見れる項目や、特別会員専用ページなどの制御で使うことを想定しています。
362
+
363
+
364
+
365
+ ```java
366
+
367
+ /**
368
+
369
+ * 会員ランクを表す列挙
370
+
371
+ */
372
+
373
+ enum MemberRank {
374
+
375
+
376
+
377
+ /** 一般会員 */
378
+
379
+ GENERAL(1) {
380
+
381
+ @Override
382
+
383
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
384
+
385
+ // 一般会員は定価のまま
386
+
387
+ return catalogPrice;
388
+
389
+ }
390
+
391
+
392
+
393
+ @Override
394
+
395
+ public BigDecimal getPoint(BigDecimal totalPrice) {
396
+
397
+ // 一般会員は購入金額の1%をポイント付与
398
+
399
+ BigDecimal percentage = new BigDecimal("0.01");
400
+
401
+ return totalPrice.multiply(percentage).setScale(0, BigDecimal.ROUND_DOWN);
402
+
403
+ }
404
+
405
+
406
+
407
+ @Override
408
+
409
+ public boolean isSpecialMember() {
410
+
411
+ // 一般会員は特別会員でない
412
+
413
+ return false;
414
+
415
+ }
416
+
417
+ },
418
+
419
+
420
+
421
+ /** シルバー会員 */
422
+
423
+ SILVER(2) {
424
+
425
+ @Override
426
+
427
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
428
+
429
+ // 5%引き
430
+
431
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.05"));
432
+
433
+ return catalogPrice.subtract(discountPrice);
434
+
435
+ }
436
+
437
+
438
+
439
+ @Override
440
+
441
+ public BigDecimal getPoint(BigDecimal totalPrice) {
442
+
443
+ // シルバー会員は購入金額の2%をポイント付与
444
+
445
+ BigDecimal percentage = new BigDecimal("0.02");
446
+
447
+ return totalPrice.multiply(percentage).setScale(0, BigDecimal.ROUND_DOWN);
448
+
449
+ }
450
+
451
+
452
+
453
+ @Override
454
+
455
+ public boolean isSpecialMember() {
456
+
457
+ // シルバー会員は特別会員でない
458
+
459
+ return false;
460
+
461
+ }
462
+
463
+ },
464
+
465
+
466
+
467
+ /** ゴールド会員 */
468
+
469
+ GOLD(3) {
470
+
471
+ @Override
472
+
473
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
474
+
475
+ // 10%引き
476
+
477
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.1"));
478
+
479
+ return catalogPrice.subtract(discountPrice);
480
+
481
+ }
482
+
483
+
484
+
485
+ @Override
486
+
487
+ public BigDecimal getPoint(BigDecimal totalPrice) {
488
+
489
+ // ゴールド会員は購入金額の3%をポイント付与
490
+
491
+ BigDecimal percentage = new BigDecimal("0.03");
492
+
493
+ return totalPrice.multiply(percentage).setScale(0, BigDecimal.ROUND_DOWN);
494
+
495
+ }
496
+
497
+
498
+
499
+ @Override
500
+
501
+ public boolean isSpecialMember() {
502
+
503
+ // ゴールド会員は特別会員
504
+
505
+ return true;
506
+
507
+ }
508
+
509
+ };
510
+
511
+
512
+
513
+ /**
514
+
515
+ * @param catalogPrice 定価
516
+
517
+ * @return ランクに応じた金額
518
+
519
+ */
520
+
521
+ public abstract BigDecimal getPrice(BigDecimal catalogPrice);
522
+
523
+
524
+
525
+ /**
526
+
527
+ * @param totalPrice 購入合計金額
528
+
529
+ * @return ランクに応じたポイント数
530
+
531
+ */
532
+
533
+ public abstract BigDecimal getPoint(BigDecimal totalPrice);
534
+
535
+
536
+
537
+ /**
538
+
539
+ * 特別会員かどうかを返す。
540
+
541
+ * <pre>
542
+
543
+ * 特別会員とはゴールド会員以上の会員のこと。
544
+
545
+ * (現状、ゴールド会員が最高ランクだが、来年にはプラチナ会員を導入予定)
546
+
547
+ * </pre>
548
+
549
+ *
550
+
551
+ * @return true..特別会員
552
+
553
+ */
554
+
555
+ public abstract boolean isSpecialMember();
556
+
557
+
558
+
559
+ /** 各列挙が持つ値 */
560
+
561
+ private int value;
562
+
563
+
564
+
565
+ /**
566
+
567
+ * コンストラクタ
568
+
569
+ */
570
+
571
+ private MemberRank(int value) {
572
+
573
+ this.value = value;
574
+
575
+ }
576
+
577
+
578
+
579
+ /**
580
+
581
+ * ファクトリー
582
+
583
+ */
584
+
585
+ public static MemberRank of(int value) {
586
+
587
+ return Stream.of(MemberRank.values()).filter(r -> r.value == value)
588
+
589
+ .findFirst().orElseThrow(IllegalArgumentException::new);
590
+
591
+ }
592
+
593
+ }
594
+
595
+ ```

1

追記

2016/04/06 04:40

投稿

root_jp
root_jp

スコア4666

test CHANGED
@@ -131,3 +131,217 @@
131
131
  BigDecimal price = getMember().getMemberRank().getPrice(catalogPrice);
132
132
 
133
133
  ```
134
+
135
+
136
+
137
+ ---
138
+
139
+ ###**追記**
140
+
141
+ > MemberクラスのmemberRankプロパティに、各会員の状態を持たせる場合、どのような実装があり得ますか?
142
+
143
+
144
+
145
+ 問題はこれです。
146
+
147
+ 通常よくあるのは、データベースの会員情報から MemberRank を作成したいわけですから、
148
+
149
+ O/Rマッパーが Member取得時に自動で入れてくれたりもします。
150
+
151
+ データベースの値を MemberRank Enum に変換してくれます。
152
+
153
+
154
+
155
+ そういうのを省いて考えた場合どうなるかというと
156
+
157
+ 例えば、以下のような感じだと台無しなわけです。
158
+
159
+ ```java
160
+
161
+ if (rank.equals("general")) {
162
+
163
+ member.setMemberRank(MemberRank.GENERAL);
164
+
165
+ } else if (rank.equals("silver")) {
166
+
167
+ member.setMemberRank(MemberRank.SILVER);
168
+
169
+ } else if (rank.equals("gold")) {
170
+
171
+ member.setMemberRank(MemberRank.GOLD);
172
+
173
+ }
174
+
175
+ ```
176
+
177
+
178
+
179
+ こういった場合は、MemberRank に以下のようなファクトリーメソッドを用意するといいです。
180
+
181
+ ```java
182
+
183
+ public static MemberRank of(String name) {
184
+
185
+ return MemberRank.valueOf(name.toUpperCase());
186
+
187
+ }
188
+
189
+ ```
190
+
191
+
192
+
193
+ そうすると、以下のように設定できます。
194
+
195
+ ```java
196
+
197
+ // rank は、"general", "silver", "gold" の文字列
198
+
199
+ member.setMemberRank(MemberRank.of(rank));
200
+
201
+ ```
202
+
203
+
204
+
205
+ データに "general" などの文字列ではなく、
206
+
207
+ 一般会員 = 1, シルバー会員 = 2, ゴールド会員 = 3 などのように
208
+
209
+ 数値として持ちたいという事も多いでしょう。
210
+
211
+ その時は、MemberRankを以下のようにします。
212
+
213
+
214
+
215
+ ```java
216
+
217
+ /**
218
+
219
+ * 会員ランクを表す列挙
220
+
221
+ */
222
+
223
+ enum MemberRank {
224
+
225
+
226
+
227
+ /** 一般会員 */
228
+
229
+ GENERAL(1) {
230
+
231
+ @Override
232
+
233
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
234
+
235
+ // 一般会員は定価のまま
236
+
237
+ return catalogPrice;
238
+
239
+ }
240
+
241
+ },
242
+
243
+
244
+
245
+ /** シルバー会員 */
246
+
247
+ SILVER(2) {
248
+
249
+ @Override
250
+
251
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
252
+
253
+ // 5%引き
254
+
255
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.05"));
256
+
257
+ return catalogPrice.subtract(discountPrice);
258
+
259
+ }
260
+
261
+ },
262
+
263
+
264
+
265
+ /** ゴールド会員 */
266
+
267
+ GOLD(3) {
268
+
269
+ @Override
270
+
271
+ public BigDecimal getPrice(BigDecimal catalogPrice) {
272
+
273
+ // 10%引き
274
+
275
+ BigDecimal discountPrice = catalogPrice.multiply(new BigDecimal("0.1"));
276
+
277
+ return catalogPrice.subtract(discountPrice);
278
+
279
+ }
280
+
281
+ };
282
+
283
+
284
+
285
+ /** 各列挙が持つ値 */
286
+
287
+ private int value;
288
+
289
+
290
+
291
+ /**
292
+
293
+ * コンストラクタ
294
+
295
+ */
296
+
297
+ private MemberRank(int value) {
298
+
299
+ this.value = value;
300
+
301
+ }
302
+
303
+
304
+
305
+ /**
306
+
307
+ * @param catalogPrice 定価
308
+
309
+ * @return ランクに応じた金額
310
+
311
+ */
312
+
313
+ public abstract BigDecimal getPrice(BigDecimal catalogPrice);
314
+
315
+
316
+
317
+ /**
318
+
319
+ * ファクトリー
320
+
321
+ */
322
+
323
+ public static MemberRank of(int value) {
324
+
325
+ return Stream.of(MemberRank.values()).filter(r -> r.value == value)
326
+
327
+ .findFirst().orElseThrow(IllegalArgumentException::new);
328
+
329
+ }
330
+
331
+ }
332
+
333
+ ```
334
+
335
+
336
+
337
+ そうすると、以下のように設定できます。
338
+
339
+ ```java
340
+
341
+ // rank は、1, 2, 3 の数値
342
+
343
+ member.setMemberRank(MemberRank.of(rank));
344
+
345
+ ```
346
+
347
+