Skip to content

Lotto 숙제 제출#1

Open
yenny07 wants to merge 34 commits intozeepy-harvard:yenny07from
yenny07:yenny07
Open

Lotto 숙제 제출#1
yenny07 wants to merge 34 commits intozeepy-harvard:yenny07from
yenny07:yenny07

Conversation

@yenny07
Copy link
Collaborator

@yenny07 yenny07 commented Mar 6, 2021

예외 처리도 못하고 보너스번호 중복 방지도 못하고 열거체도 하나뿐이고..
클래스가 이렇게 하나뿐이어도 되는지 의구심도 들고 아쉬운 게 많아요.. 피드백 주시면 더 고쳐보겠습니다..!!!!

yenny07 added 7 commits March 5, 2021 15:56
- buyTickets() 구현
- makeTicket() 구현
- buyTickets()에서 일정 장수의 티켓을 생성하는 로직을 makeTickets()로 분리
- 기존 makeTicket()  -> createNumbers()
- 차례대로 메소드를 호출하는 run() 작성
- inputWinningNumber()
- inputBonusNumber()
- enum Rank
- 맞춘 번호 개수를 구하는 matcher()
- 당첨된 등수를 구하는 getRank()
Copy link

@KimGyeong KimGyeong left a comment

Choose a reason for hiding this comment

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

코멘트를 남기기엔 너무 큰 요구 사항들이 많아서 이렇게 따로 리스트를 정리해 적어드립니다.

1.테스트 코드 작성하기
2. Ticket Class 구현하기
3. 당첨 번호를 담당하는 Class 구현하기
4. Input, Output을 담당하는 Class 구현하기
5. 각 예외 발생 상황에 따른 예외처리 하기.

자바는 객체지향 프로그래밍 언어이고, 객체지향 프로그래밍을 지향해야 해요. 클래스를 나누는 것부터 시작을 해봅시다.
과제의 학습목표만을 따르지 말고, 이전의 학습 목표들과 더 넓게 학습 목표들을 잡아보세요. 막연하게 돌아가는 애플리케이션을 만드는 것이 목적이 아닌 숙제들이니까요.
수정한 후에 요청해주세요.

Comment on lines 9 to 13
int ticketCount;
int bonusNumber;
List<List<Integer>> tickets;
List<Integer> winningNumber;
int[] hits;

Choose a reason for hiding this comment

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

초기화 하지 않은 값들은 위험해요! 만약 초기화가 되지 않은 값에 접근을 한다면 NullPointerException이 발생하겠죠? 아래에 초기화를 해주면서 선언을 해주면 좋을 것 같습니다.

Comment on lines 26 to 27
String inputMoney = scanner.nextLine();
int ticketCount = Integer.parseInt(inputMoney) / 1000;

Choose a reason for hiding this comment

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

Scanner에는 Integer값을 받는 함수도 존재합니다! 공부를 해볼까요?

Copy link

@KimGyeong KimGyeong left a comment

Choose a reason for hiding this comment

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

저번 미션보다 많이 발전한 모습이 눈에 띱니다. 좋아지고 있어요!!
클래스의 책임과 메소드의 책임에 대해 생각해보면서 리팩토링을 진행하시면 좋을 것 같습니다.
이것과 더불어 코멘트들 확인해주세요. 수정한 후에 다시 리뷰 요청을 해주시면 되겠습니다.

Comment on lines 34 to 36
hitCount = ticket.stream()
.filter(winningNumber::contains)
.count();

Choose a reason for hiding this comment

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

👍

Comment on lines 44 to 64
private Rank getRank(long hitCount, Ticket ticket, int bonusNumber) {
Rank rank = null;

switch ((int) hitCount) {
case 3:
rank = Rank.THREE;
break;
case 4:
rank = Rank.FOUR;
break;
case 5:
rank = (ticket.contains(bonusNumber)) ? Rank.BONUS : Rank.FIVE;
break;
case 6:
rank = Rank.SIX;
break;
default:
rank = null;
}

return rank;

Choose a reason for hiding this comment

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

Rank를 반환해주는 메소드네요. Rank에게 책임을 전가하면 어떨까요? Rank의 메소드로 만들면 좋을 것 같아요.

Comment on lines 11 to 14
for (Rank rank : ranks) {
System.out.println(rank.getString() + hits[rank.ordinal()] + "개");
totalPrize += rank.getPrize() * hits[rank.ordinal()];
}

Choose a reason for hiding this comment

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

Output 클래스는 오직 출력만을 담당하는 클래스여야 해요. 이 로직은 다른 곳에서 수행하여 그 값들만 받아 출력하는 방법은 없을까요?

Comment on lines 26 to 28
public String getString() {
return hit + "개 일치 (" + prize + "원) - ";
}

Choose a reason for hiding this comment

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

get~의 메소드명은 일반적으로 getter 메소드로써 사용을 합니다. 필드의 값을 반환하기 위해서요.
여기서 사용하는 String, 즉 "개 일치 (" + prize + "원) - "Output 클래스에서 사용하는 것을 권장드립니다.

}

int ticketCount = inputMoney / 1000;
System.out.println(ticketCount + "개를 구매했습니다.");

Choose a reason for hiding this comment

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

Output클래스가 있음에도 print메소드를 사용하네요. 어떻게 수정하면 main 클래스에서 직접적으로 System.out.println 메소드를 호출하지 않을 수 있을까요?

Comment on lines 8 to 10
public class WinningNumber extends ArrayList<Integer> {

private int bonusNumber;

Choose a reason for hiding this comment

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

상속은 조심해서 사용해야 합니다. 만약 WinningNumberSet이라는 자료구조로 변경 될 경우에, 이 클래스에서 사용하는 ArrayList의 메소드들을 모두 수정해줘야 하겠죠? 상속이 아닌 필드값을 ListArrayList로 변경하는 것은 어떨까요?

hitCount = ticket.stream()
.filter(winningNumber::contains)
.count();
if (hitCount >= 3) {

Choose a reason for hiding this comment

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

요구사항 중 하나인 indent(인덴트, 들여쓰기) depth를 2단계에서 1단계로 줄여보세요.가 지켜지지 않네요. 어떻게 수정하는 것이 좋을까요?

Copy link

@KimGyeong KimGyeong left a comment

Choose a reason for hiding this comment

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

이전보다 많이 좋아졌네요. 여기서 로또 번호들이 enum으로 구현된다면 어떨까요? 그렇게 된다면 1부터 45인 것에 대해 덜 신경써도 되겠죠? 현재 코드에서 만약 로또번호가 4~50으로 변경된다면 1부터 45인 것들을 모두 다 찾아서 고쳐야합니다. 변경 가능성과 확장 가능성을 모두 열어두고 그 상황에 어떻게 해야 더 수월한 작업이 이루어질 수 있을지 고민해봅시다.
수정할 사항들이 조금 더 있어요. 아래에 적어둘게요.

  1. Input과 Output은 main 메소드에서만 사용하게 변경할 수 있을까요? 입력과 출력, 그리고 비즈니스 로직의 흐름을 main 메소드에서만 확인할 수 있게요.
  2. 예외 처리가 아직 많이 부족하네요. 본인이 생각하고 발견할 수 있는 예외 처리들을 모두 구현해보세요. 또한 그 케이스에 따른 테스트 코드들도 생기면 더욱 좋구요.

수정한 후에 리뷰 요청 다시 해주세요!

case 4:
return Rank.FOUR;
case 5:
return (ticket.contains(bonusNumber)) ? Rank.BONUS : Rank.FIVE;

Choose a reason for hiding this comment

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

👍

private void calculateHits(WinningNumber winningNumber, long hitCount, Ticket ticket) {
if (hitCount >= 3) {
Rank rank = Rank.getRank(hitCount, ticket, winningNumber.getBonusNumber());
hits[rank.ordinal()] += 1;

Choose a reason for hiding this comment

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

ranknull이면 어떻게 되나요?

Comment on lines 7 to 25

public Ticket() {
createNumbers();
}

public Ticket(ArrayList<Integer> testInput) {
this.addAll(testInput);
}

private void createNumbers() {

for (int i = 1; i <= 45; i++) {
this.add(i);
}

Collections.shuffle(this);
this.subList(6, 45).clear();
Collections.sort(this);
}

Choose a reason for hiding this comment

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

Suggested change
public Ticket() {
createNumbers();
}
public Ticket(ArrayList<Integer> testInput) {
this.addAll(testInput);
}
private void createNumbers() {
for (int i = 1; i <= 45; i++) {
this.add(i);
}
Collections.shuffle(this);
this.subList(6, 45).clear();
Collections.sort(this);
}
private List<Integer> ticketNumbers;
public Ticket() {
this.ticketNumbers = createNumbers();
}
public Ticket(ArrayList<Integer> testInput) {
this.ticketNumbers = testInput;
}
private List<Integer> createNumbers() {
List<Integer> numbers = new ArrayList<>();
for (int i = 1; i <= 45; i++) {
numbers.add(i);
}
Collections.shuffle(numbers);
numbers.subList(6, 45).clear();
return Collections.sort(numbers);
}

이런 형태이면 상속을 제거해도 되겠죠? 상속을 사용했을 때의 단점은 매우 강합니다.
예를 들어, List가 아닌 Set 자료구조를 사용하라는 요구사항이 발생했을 경우에는 변경해야 할 사항들과 고려해야 할 사항들이 많아지거든요.
상속에 대해 공부해보면 좋을 것 같아요.

Copy link

@KimGyeong KimGyeong left a comment

Choose a reason for hiding this comment

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

코멘트를 여러가지 남겼어요. 변수명에는 원시타입을 넣지 않는게 좋을 것 같아요. 참고할만한 자료를 같이 작성해줄게요. (참고자료)
예외에 따른 테스트도 추가하면 좋을 것 같아요. 예외 처리가 되는지 안되는지 확인할 수 있겠죠?
주요 로직에 있는 예외 처리에 대한 피드백은 다음에 남길게요.
수정하고 다시 리뷰 요청 해주세요!

Comment on lines 24 to 29
Numbers[] lottoNum = Numbers.values();
List<Numbers> sixNumbers = new ArrayList<>();

for (String num : stringNumber) {
sixNumbers.add(lottoNum[Integer.parseInt(num)]);
}

Choose a reason for hiding this comment

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

Suggested change
Numbers[] lottoNum = Numbers.values();
List<Numbers> sixNumbers = new ArrayList<>();
for (String num : stringNumber) {
sixNumbers.add(lottoNum[Integer.parseInt(num)]);
}
List<Numbers> lottoNumbers = Arrays.stream(stringNumber)
.map(number -> Integer.parseInt(number))
.map(number -> Numbers.get(number))
.collect(Collections.toList());

스트림을 활용하면 여러 변수 선언을 줄일 수 있겠죠? 대신 Numbers 에서 메소드가 하나 필요하네요.
스트림을 사용해보는건 어때요?

Choose a reason for hiding this comment

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

mapToInt을 활용하는 방법도 있겠군요.

Comment on lines 38 to 39
Numbers[] lottoNum = Numbers.values();
Numbers bonusNumber = lottoNum[intBonusNumber];

Choose a reason for hiding this comment

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

Numbers를 모두 가져온다면 사용하지 않는 친구들까지 모두 불러오는거겠죠? 메소드를 만들어 필요한 아이들만 꺼내오는건 어떨까요?

Comment on lines +62 to +63
if (!(sixNumbers.stream()
.allMatch(new HashSet<>()::add))) {

Choose a reason for hiding this comment

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

Set을 활용하는 방법 좋네요! 👍


public WinningNumber() {
sixNumbers = new ArrayList<>();
bonusNumber = Numbers.ZERO;

Choose a reason for hiding this comment

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

당첨번호에 보너스 숫자가 있어야 하는데, 0으로 초기화를 하는게 옳을까요?

package lotto;

public enum Numbers {
ZERO(0),

Choose a reason for hiding this comment

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

이 상수는 어디서 사용하나요?

Comment on lines 41 to 46
List<Integer> intNumbers = new ArrayList<>();
for (int i = 0; i < ticketNumbers.size(); i++) {
intNumbers.add(ticketNumbers.get(i).getNum());
}

return intNumbers;

Choose a reason for hiding this comment

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

이것도 stream으로 간결하게 할 수 있지 않을까요?

Comment on lines 28 to 40
public void setSixNumbers() {
Input input = new Input();
sixNumbers = input.inputWinningNumber();
}

public void setBonusNumber() {
Input input = new Input();
bonusNumber = input.inputBonusNumber();

if (sixNumbers.contains(bonusNumber)) {
throw new IllegalArgumentException("보너스 번호가 이미 당첨 번호에 존재합니다.");
}
}

Choose a reason for hiding this comment

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

setter를 사용하지 않고 할 수 있는 방법은 없을까요?

Copy link

@KimGyeong KimGyeong left a comment

Choose a reason for hiding this comment

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

더 이상 수정할 것은 크게 보이지 않네요. 남긴 코멘트만 한번 더 생각해보면 좋을 것 같아요.
처음과 비교했을 때 더 좋은 코드로 보이나요? 본인의 생각을 가지고 본인만의 스타일을 고수해보는 것도 좋을 것 같아요. 고생했습니다.

private void inputSixNumbers() {
Input input = new Input();
String userInputNumbers = input.inputLine();
String[] commaRemoved = userInputNumbers.split(",");

Choose a reason for hiding this comment

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

입력이 1, 2 , 3이라면 ["1","2 "," 3"]과 같이 띄어쓰기도 같이 나뉘어지지 않나요?

Comment on lines +37 to +62
private void inputSixNumbers() {
Input input = new Input();
String userInputNumbers = input.inputLine();
String[] commaRemoved = userInputNumbers.split(",");

List<Numbers> sixNumbers = Arrays.stream(commaRemoved)
.mapToInt(Integer::parseInt)
.mapToObj(Numbers::get)
.collect(Collectors.toList());

input.validateWinningNumber(sixNumbers);

this.sixNumbers = sixNumbers;
}

private void inputBonusNumber() {
Input input = new Input();
int userInputNumber = input.inputInt();
Numbers bonusNumber = Numbers.get(userInputNumber);

if (sixNumbers.contains(bonusNumber)) {
throw new IllegalArgumentException("보너스 번호가 이미 당첨 번호에 존재합니다.");
}

this.bonusNumber = bonusNumber;
}

Choose a reason for hiding this comment

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

입력을 받은 값을 바탕으로 WinningNumber 객체 생성을 하면 어떨까요? Input 클래스와 WinningNumber 클래스의 의존성을 제거할 수 있고, 필드값에 대한 예외처리를 클래스 메소드에서 안해도 되니까요.

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