간단한 로또 발매기 구현
- 로또 구입 금액 입력
- 구입 금액은 1000원 단위로 입력 받는다
- 1000원 단위로 나뉘지 않는다면 예외처리
- 1000원 이하의 값이 입력되면 예외처리
- 정수가 아닌 값이 입력되면 예외처리
- 음수가 입력되면 예외처리
- int의 범위를 넘어선 값이 들어오면 예외처리
- 당첨 번호 입력
- 6개의 당첨 번호를 입력 받는다
- 번호는 ,(쉼표)로 구분한다
- 번호가 중복되면 예외처리
- 번호가 1~45의 범위를 넘어서면 예외처리
- 번호의 개수가 6개가 아니라면 예외처리
- 잘못된 구분자가 입력 되었다면 예외처리
- 정수가 아닌 값이 입력 되었다면 예외처리
- 보너스 번호 입력
- 1개의 보너스 번호를 입력 받는다
- 번호가 1~45의 범위를 넘어서면 예외처리
- 정수가 아닌 값이 입력 되었다면 예외처리
- 앞서 입력된 당첨 번호와 중복된다면 예외처리
- 로또 생성
- 입력된 구입 금액에 해당하는 만큼 로또를 발행한다 (1장의 가격은 1000원)
- 당첨번호와 입력 번호를 비교하여 당첨 여부 결정
- 3개 이상의 번호가 일치한다면 당첨
- 3개 미안의 번호가 일치한다면 탈락
- 일치 번호 개수에 따른 당첨 등수 결정
- 1등: 6개 번호 일치
- 2등: 5개 번호 + 보너스 번호 일치
- 3등: 5개 번호 일치
- 4등: 4개 번호 일치
- 5등: 3개 번호 일치
- 등수에 따른 당첨 금액 결정
- 1등: 2,000,000,000원
- 2등: 30,000,000원
- 3등: 1,500,000원
- 4등: 50,000원
- 5등: 5,000원
- 총 당첨금을 계산한다
- 당첨 금액이 int 범위를 넘었을 경우 예외처리
- 구입 금액과 총 당첨금을 비교하여 수익률을 계산한다 (수익률은 소수점 둘째 자리에서 반올림)
- 발행한 로또 수량 출력
- 발행한 로또 번호를 오름차순으로 정렬하여 출력
- 당첨 내역을 출력
- 수익률을 출력
- 에외처리가 되었다면 에러 메시지 출력 후 그 부분부터 입력을 다시 받는다
Before:
- 모델 클래스에서 필드 값을 나중에 설정할 때 setter 메소드를 사용하는 방식이었습니다.
- 객체의 상태가 가변적이었고, 예기치 않은 변경으로 인해 코드 유지보수 시 사이드 이펙트가 발생할 가능성이 있었습니다.
After:
- 모델의 불변성을 보장하기 위해 setter 사용을 지양하고, 일부 필드만 초기화된 인스턴스를 생성한 후, 추가 필드가 필요한 시점에 기존 인스턴스를 기반으로 새로운 인스턴스를 생성하는 방식으로 변경했습니다.
- 예:
WinningNumbers클래스는 처음에 보너스 번호 없이 생성된 후, 보너스 번호가 필요할 때createWithBonusNumber메서드를 통해 새로운 인스턴스를 생성합니다.WinningStatistic클래스도 비슷한 방식으로 처리하여, 사용되지 않는 이전 인스턴스는 가비지 컬렉션을 통해 관리되도록 했습니다.
Before:
- 모델 객체의 내부 필드를 get 메소드를 통해 외부로 노출한 후, 외부 클래스에서 해당 데이터를 활용해 로직을 처리했습니다.
- 예:
Lotto객체의getNumbers메서드를 통해 번호 리스트를 가져온 후, 외부에서 당첨 번호와 비교하는 방식이었습니다.
After:
- get 메서드 대신, 모델 자체에서 필요한 로직을 처리하고 결과를 반환하도록 개선했습니다.
- 예:
WinningNumbers와Lotto모델 간의 협력 메서드를 통해 번호 일치 여부를 계산하도록 구현했습니다.getMatchCount메서드를 사용해Lotto객체와 비교하여 일치 번호 개수를 반환하도록 했습니다..
Before:
- 컨트롤러 내에서 입력을 처리하거나 반복 로직을 단순히 반복적으로 작성했습니다.
- Lottos에 존재하는 n개의 Lotto에 특정 로직을 각각 적용하기 위해 get으로 List를 받아오고 반복문으로 로직을 적용하였습니다.
After:
- 함수형 인터페이스를 활용하여 중복된 입력 처리 로직을 재사용할 수 있도록 개선했습니다.
InputSupplier<T>인터페이스를 정의하여LottoController에서 while-try-catch 로직을 간결하고 재사용 가능하게 만들었습니다.Lottos클래스에서Consumer를 활용하여 반복 작업을 내부적으로 처리했습니다.Lottos클래스는Consumer를 매개변수로 받아 각Lotto객체에 대해 작업을 수행하도록 구현했습니다.
Before:
- 객체 생성과 관련된 로직이 서비스나 컨트롤러에 혼재되어 있었고, 특정 요구사항에 맞게 코드가 딱딱하게 고정되어 있었습니다.
After:
- 인터페이스와 의존성 주입:
Validator,LottoNumberGeneratorStrategy등의 인터페이스를 도입해 확장 가능성을 열어두었습니다. 다양한 구현체를 쉽게 추가할 수 있도록 설계하여, 유지보수와 확장이 용이하게 했습니다. - 팩토리 패턴:
LottoFactory,WinningNumbersFactory등을 사용하여 객체 생성 로직을 분리했습니다. 이는 객체 생성과 비즈니스 로직을 분리해 코드 응집도를 높였습니다. - Facade 패턴:
ValidatorFacade와ViewFacade,LottoFacade를 통해 여러 컴포넌트와의 복잡한 의존 관계를 단순화하였고 Controller에서 통합된 인터페이스를 이용하여 로직을 처리함으로써 가독성을 높였습니다.