Search
Duplicate

3. [클린 코드 with Java] 3단계 - 로또 게임(2등)

링크
점수
⭐️⭐️⭐️⭐️
완료일
2023/05/05
상태
완료
유형
인강

로또 게임(2등)

기능요구사항

2등을 위해 추가 번호를 하나 더 추첨한다.
당첨 통계에 2등도 추가해야 한다.
[... 생략 ...] 지난 주 당첨 번호를 입력해 주세요. 1, 2, 3, 4, 5, 6 보너스 볼을 입력해 주세요. 7 당첨 통계 --------- 3개 일치 (5000)- 14개 일치 (50000)- 05개 일치 (1500000)- 05개 일치, 보너스 볼 일치(30000000) - 06개 일치 (2000000000)- 0개 총 수익률은 0.35입니다.(기준이 1이기 때문에 결과적으로 손해라는 의미임)
Java
복사

프로그래밍 요구사항

모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외
java enum을 적용해 프로그래밍을 구현한다.
규칙 8: 일급 콜렉션을 쓴다.
indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다.
함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.
자바 코드 컨벤션을 지키면서 프로그래밍한다.
else 예약어를 쓰지 않는다.

힌트

일급 콜렉션을 쓴다.
6개의 숫자 값을 가지는 java collection을 감싸는 객체를 추가해 구현해 본다.
하드 코딩을 하지 않기 위해 상수 값을 사용하면 많은 상수 값이 발생한다. 자바의 enum을 활용해 상수 값을 제거한다. 즉, enum을 활용해 일치하는 수를 로또 등수로 변경해 본다.

기능 목록 및 commit 로그 요구사항

기능을 구현하기 전에 README.md 파일에 구현할 기능 목록을 정리해 추가한다.
git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다.

피드백

리뷰어 : 이 enum에서만 관리하면 되므로, enum에서 해당 필드를 public하게 노출시키고 여기 이 추출들은 제거하는 것이 조금 더 자연스러운 구현인 듯 합니다.
생각정리 : 이넘에서 표현해 주었는데, 내부에서 굳이 필드를 WinningAmountByRank 으로는 줄필요가 없을 것같다.
public enum WinningAmountByRank { FIRST(WinningAmountByRank.FIRST_PLACE, 2000000000, "FIRST_PLACE"), SECOND(WinningAmountByRank.SECOND_PLACE, 1500000, "SECOND_PLACE"), THIRD(WinningAmountByRank.THIRD_PLACE, 50000, "THIRD_PLACE"), FOURTH(WinningAmountByRank.FOURTH_PLACE, 5000, "FOURTH_PLACE"), EMPTY(WinningAmountByRank.EMPTY_PLACE, 0, "EMPTY_PLACE"); public static final int FIRST_PLACE = 6; public static final int SECOND_PLACE = 5; public static final int THIRD_PLACE = 4; public static final int FOURTH_PLACE = 3; public static final int EMPTY_PLACE = 0;
Java
복사
다음과 같이 변경
public enum WinningAmountByRank { FIRST(6, 2000000000, "FIRST_PLACE"), BONUS(37, 30000000, "BONUS_PLACE"), SECOND(5, 1500000, "SECOND_PLACE"), THIRD(4, 50000, "THIRD_PLACE"), FOURTH(3, 5000, "FOURTH_PLACE"), EMPTY(0, 0, "EMPTY_PLACE"); private final int rank; private final int amount; private final String key;
Java
복사
리뷰어 : LottoService 에서 또 의견을 드리겠지만, 서비스 객체가 파라메터에 따라 생성되는 것이 조금 신기하고 어색하게 느껴집니다. 생성자로 lottoCount 가 넘어가야 할 이유가 있으려나요?
생각정리 : 서비스객체를 생성자를 써서 필드를 남길필요가 없었는데, 싱글톤 패턴이라고 생각했을 때 Thread safe에 맞지 않을 것 같았다.
public class LottoService { private Lottos lottos; public LottoService(int lottoCount) { this.lottos = new Lottos(lottoCount); }
Java
복사
다음과 같이 변경
singleton 적용
public class LottoService { // singleton 적용 private static LottoService lottoService = null; public static LottoService createLottoService() { if (Objects.isNull(lottoService)) { return new LottoService(); } return lottoService; }
Java
복사
리뷰어 : 스트림 기반으로 개선해 보시면 좋겠네요!
생각정리 : 스트림 안에서 너무 많은 기능을 첨부하는 소스코드를 보았다. 복잡해서 거부감이 있었는데, 하나의 기능에 집중하는 스트림을 사용한다면, 충분히 가독성 면에서도 좋다고 생각된다.
public void calculatorProfit() { double winningAmount = 0; for (Lotto lotto : lottos.getLottos()) { int winningCount = getWinningResult(lotto); WinningAmountByRank from = WinningAmountByRank.from(winningCount); winningResult.put(from.getKey(), winningResult.getOrDefault(from.getKey(), 0) + 1); winningAmount += from.getAmount(); } profit = winningAmount / purchaseAmount; }
Java
복사
다음과 같이 변경
public double calculatorProfit(Lottos lottos, int purchaseAmount) { double sum = lottos.getLottos() .stream() .mapToInt(lotto -> WinningAmountByRank.from(getWinningResult(lotto)).getAmount()).sum(); return sum / purchaseAmount; }
Java
복사

후기

오늘은 로또 3단계 로또 게임 2등을 진행하였다. 서비스 객체로 생각했을 때, 필드값을 지정해 준다면 과연 thread safe에 안전한가에 대해서 다시 한번 생각할 수 있는 기회였다. 테스트 코드도 객체를 완성할 때마다 작성할 수 있도록 구현해 보자!
깃허브링크 :
3055
pull
출처