Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[로또] 채민아 미션 제출합니다. #93

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

chaemina
Copy link

@chaemina chaemina commented Nov 4, 2024

로또 발매기

프로젝트 소개

로또 발매기 프로젝트는 사용자가 구입 금액을 입력하면 해당 개수의 로또 번호를 발행하고, 사용자가 입력한 당첨 번호와 비교하여 당첨 여부와 수익률을 계산하는 프로그램입니다. 이 프로그램은 Kotlin으로 작성되었으며, MVP 구조로 설계되었습니다.

주요 기능

  1. 사용자 입력 처리

    • 구입 금액, 당첨 번호, 보너스 번호를 입력받고, 입력값의 유효성을 검증합니다.
  2. 로또 번호 생성

    • 구입 금액에 맞는 수량의 로또를 발행하며, 각 로또는 중복되지 않는 6개의 번호로 구성됩니다.
  3. 당첨 번호 관리

    • 당첨 번호와 보너스 번호를 입력받아 저장하고 관리합니다.
  4. 당첨 결과 계산

    • 발행된 로또와 당첨 번호를 비교하여 등수에 따라 당첨 여부를 계산합니다.
  5. 수익률 계산

    • 당첨 결과에 따라 수익률을 계산하여 표시합니다.
  6. 에러 처리 및 메시지 관리

    • 유효하지 않은 입력값이나 시스템 에러 발생 시 적절한 에러 메시지를 출력합니다.

기능 구현 순서

  1. 상수 관리 클래스 생성

    • 에러 메시지, 로또 가격, 숫자 범위 등의 고정값을 Constants로 미리 작성합니다.
  2. Model

    • 로또 번호 생성 로직 구현: 1~45 범위의 중복되지 않는 6개 번호를 생성합니다.
    • 당첨 번호와 보너스 번호 관리: 사용자 입력값을 저장하고 검증합니다.
    • 당첨 계산 및 수익률 계산 로직 구현: 사용자 로또와 당첨 번호를 비교하고, 일치하는 번호에 따라 당첨 결과와 수익률을 계산합니다.
  3. View

    • 사용자 입력 요청 화면 구현: 구입 금액, 당첨 번호, 보너스 번호 입력받기.
    • 로또 번호 출력: 발행된 로또 번호를 오름차순으로 정렬하여 출력합니다.
    • 당첨 결과 및 수익률 출력: 당첨 통계와 수익률을 계산하여 화면에 표시합니다.
    • 에러 메시지 출력: 예외 발생 시 에러 메시지를 사용자에게 보여줍니다.
  4. Presenter

    • 사용자 입력 처리 로직 구현: Model에 데이터를 전달하고, 유효성 검사를 수행합니다.
    • 로또 발행 요청 및 결과 전달: Model에서 생성된 로또 번호를 View에 전달하여 출력합니다.
    • 당첨 결과 및 수익률 전달: Model에서 계산된 당첨 결과와 수익률을 View에 전달합니다.
    • 에러 처리 로직 연결: Model에서 발생한 예외 상황을 View에 전달하여 사용자에게 에러 메시지를 표시합니다.
  5. enum 클래스 정의

    • 당첨 등수(Prize)를 enum 클래스로 정의합니다.

프로젝트 소개와, 주요기능, 기능 구현 순서를 작성함
에러메세지, 로또 가격, 숫자 범위 등의 고정값을 미리 정의
- 미리 작성해 고정값을 다른 클래스에서 참조하기 위함
RandomLottoModel 클래스에서는 로또 번호를 생성하고 관리하는 기능을 구현
- 로또 번호 생성과 번호 리스트를 관리하기 때문에 모델로 분류함
기존의 RandomLottoModel 파일의 코드를 Lotto 파일로 이동시킴
- 같은 기능의 클래스를 하나로 통일
- 하나의 클래스의 길이가 길어지는 것 방지하기 위해 검증 코드는 분리시킴
로또 번호 유효성 검사 로직을 유틸 함수로 분리함
- 추후에 입력값 검증 추가를 위해 Validator 로 명명함
로또 번호 유효성 검증하는 테스트 코드를 작성
- 각 기능 별로 작은 단위테스트를 작성
- 예외 처리 뿐만 아니라 기능도 검증
사용자가 금액을 입력한 경우, 에러 처리 하는 경우 작성
- 프레젠터가 뷰에 접근 할 수 있도록 함
- 이를 통해 프레젠터가 뷰의 구현체에 구애받지 않고, 뷰와 프레젠터의 결합도를 낮추도록 함
공통 인터페이스(에러함수), 개별 인터페이스를 분리함
- 개별 뷰에서 필요한 인터페이스만 상속 받아서 작성 할 수 있도록 수정함
- ErrorMessageView에서 메세지를 프린트 하는 showErrorMessage 함수 작성
- PurchaseView에서 금액을 입력받는 requestPurchaseAmount 함수 작성
- showErrorMessage는 ErrorMessageView에서 작성한 함수를 호출
기존의 Random API 를 pickUniqeNumbersIsRange API 로 수정함
- 지정된 요구사항을 충족시키기 위함
기존 util의 Validation 클래스에 금액 유효성 검증 함수를 추가해서 활용함
Lotto의 번호 생성 함수를 호출해서 번호를 생성함
사용자가 입력한 금액에 맞춰 로또 번호를 생성함
Validatior 클래스에 showError 함수를 추가하여 에러 메세지 호출까지 담당하도록 함- 다른 뷰 클래스에서 해당 기능만 담당하고, 간결하게 하도록 수정함
반환된 로또 리스트, 입력 받은 당첨 번호, 보너스 번호를 선언함
메인에서 각각의 뷰와 프레젠터를 연결해서 메인 기능을 완성
@FLU0RITE
Copy link

FLU0RITE commented Nov 6, 2024

3주차 고생하셨어요~

Comment on lines +12 to 32
// 모델 생성
val lottoModel = LottoModel()

// 뷰 생성
val purchaseView = PurchaseView()
val winningNumberView = WinningNumberView()
val resultView = ResultView()

// 프레젠터 생성
val purchasePresenter = PurchasePresenter(purchaseView, winningNumberView, lottoModel)
val winningNumberPresenter = WinningNumberPresenter(winningNumberView, lottoModel, resultView)
val resultPresenter = ResultPresenter(resultView, lottoModel)

// 각 뷰에 프레젠터 연결
purchaseView.setPresenter(purchasePresenter)
winningNumberView.setPresenter(winningNumberPresenter)
resultView.setPresenter(resultPresenter)

// 프로그램 시작
purchasePresenter.startPurchase()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

궁금해서 그런데 이것도 main presenter를 만들어서 그곳에서 처리할 수 있지 않나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요! 우선 코드 리뷰 해주셔서 감사합니다 :)

저 같은 경우에는 MVP 구조로 코드 작성해보는 게 처음이라서, 공부했던 이론을 바탕으로 그대로 작성했습니다.
그러나 실질적인 프로젝트에 있어서는 FLUORTIE 님께서 말씀하신대로, mainpresenter로 모듈화 하는 경우가 많고
이 접근 방식으로 코드를 다시 작성해보니 더 깔끔한 것 같다는 생각이 듭니다.
좋은 조언 감사합니다!

Comment on lines +5 to +8
interface PurchaseViewInterface {
fun requestPurchaseAmount()
fun setPresenter(presenter: PurchasePresenter)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interface에 대해 잘 몰랐는데 공부하는 계기가 되었어요 감사해요. interface를 쓰신 이유가 궁금해요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MVP에서 interface를 사용하는 것 MVP 구조의 큰 장점입니다!
뷰를 interface로 정의하여 구현하면 presenter에서 view 대신 interface 만을 참조하므로
뷰의 구현제에 구애받지 않으며 둘의 결합도가 낮아지고, 뷰를 쉽게 교체 할 수 있는 장점이 있습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants