-
Notifications
You must be signed in to change notification settings - Fork 34
[2주차] 객체지향 코드 제출(JongHyeok03 ) #43
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다!
MVC에 대한 공부를 조금 더 하시면 좋을 것 같습니다.
책임이 너무 흩어져 있지는 않은지
응집도가 너무 높지 않은지 는 사람에 따라 생각하는게 다를겁니다.
하지만 한쪽으로 기울어 진다면 좀 아쉽지 않을까 생각합니다!
그래도 많이 고민하신게 보여서 열심히 하고 계신것 같아 뿌듯합니다!
코드 리뷰 보시고 리팩토링 해보시면 좋을 것 같아요!
AppConfig 꼭 써보시길 권장드립니다!!
|
||
public static void main(String[] args) { | ||
// TODO: 프로그램 구현 | ||
InputView inputView = new InputView(); | ||
OutputView outputView = new OutputView(); | ||
|
||
Controller controller = new Controller(inputView, outputView); | ||
controller.run(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AppConfig 사용해보세용
"AppConfig 순수자바" 키워드로 검색하신 후 공부하면 좋을 것 같아요
public class Controller { | ||
private final InputView inputView; | ||
private final OutputView outputView; | ||
private final LottoService lottoService = new LottoService(); | ||
private final Validator validator = new Validator(); | ||
|
||
public Controller(InputView inputView, OutputView outputView) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
|
||
} | ||
public void run(){ | ||
int purchasedPrice = readAndValidatePurchasePrice(); | ||
LottoTickets hadLottos = lottoService.purchaseLottos(purchasedPrice); | ||
outputView.printLottos(hadLottos); | ||
List<Integer> winningNum = readAndValidateWinningNumbers(); | ||
Lotto winningLotto = new Lotto(winningNum); | ||
winningLotto.sortNumbers(); | ||
int bonusNum = readAndValidateBonusNumber(winningLotto); | ||
int[] result = LottoResultChecker.checkResult(hadLottos, winningLotto, bonusNum); | ||
outputView.printResult(result,purchasedPrice); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컨트롤러가 너무 담당하는 일이 많고, 협력 객체를 직접 생성하고 있기 때문에 결합도가 너무 높습니다.
컨트롤러는 단순히 view와 model을 연결해 주는 곳이라고 생각하시면 됩니다. 유효성 검사가 컨트롤러에 있을 필요가 있을지 생각해 보시는게 좋을 것 같습니다!
AppConfig를 사용하셔서 담당하는 일을 줄이고, DI(생성자 주입)를 사용하셔보시기 바랍니다!
private int readAndValidateBonusNumber(Lotto winningLotto) { | ||
while (true) { | ||
try { | ||
int bonusNum = inputView.readBonusNumber(); | ||
validator.validateBonusNumber(winningLotto, bonusNum); | ||
return bonusNum; | ||
} catch (IllegalArgumentException e) { | ||
outputView.printErrorMessage(e.getMessage()); | ||
} | ||
} | ||
} | ||
|
||
|
||
private int readAndValidatePurchasePrice() { | ||
while (true) { | ||
try { | ||
int purchasedPrice = inputView.readPurchasePrice(); | ||
validator.validatePurchasedAmount(purchasedPrice); | ||
return purchasedPrice; | ||
} catch (IllegalArgumentException e) { | ||
outputView.printErrorMessage(e.getMessage()); | ||
} | ||
} | ||
} | ||
|
||
private List<Integer> readAndValidateWinningNumbers() { | ||
while (true) | ||
try { | ||
List<Integer> winningNumbers = inputView.readWinningNumberInput(); | ||
validator.validateWinningNumber(winningNumbers); | ||
return winningNumbers; | ||
} catch (IllegalArgumentException e) { | ||
outputView.printErrorMessage(e.getMessage()); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
메서드 네이밍만 봐도 두가지 일을 한번에 하는걸 알 수 있는데. 이걸 과연 컨트롤러에서 검증을 하는게 맞는지, 두가지를 한번에 해도 되는지 를 고민하시면 좋을 것 같습니다.
public class Validator { | ||
|
||
public void validatePurchasedAmount(int purchasedAmount) { | ||
if (purchasedAmount < 1000 || purchasedAmount % 1000 != 0) { | ||
throw new IllegalArgumentException("[ERROR] 구매 금액은 1000원 이상, 1000원 단위로 입력해주세요"); | ||
} | ||
} | ||
|
||
public void validateWinningNumber(List<Integer> winningNumbers) { | ||
if (winningNumbers.size() != 6) { | ||
throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다."); | ||
} | ||
validateDuplicateNumbers(winningNumbers); | ||
|
||
for (Integer num : winningNumbers) { | ||
if (num < 1 || num > 45) { | ||
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); | ||
} | ||
} | ||
} | ||
|
||
private void validateDuplicateNumbers(List<Integer> winningNumbers) { | ||
Set<Integer> uniqueNumbers = new HashSet<>(winningNumbers); | ||
|
||
if (uniqueNumbers.size() != winningNumbers.size()) { | ||
throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다."); | ||
} | ||
} | ||
|
||
public void validateBonusNumber(Lotto winningLotto, int bonusNum) { | ||
if(winningLotto.getNumbers().contains(bonusNum)){ | ||
throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다."); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
음 검증 전용으로 책임을 분리한건 좋습니다.
하지만 책임 분리가 곧 클래스를 무조건 나눈다는 뜻은 아닙니다.
이 점 생각하셔서 책임을 적절한 곳에 분배해 보세요!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그리고 에러만 담당하는 클래스도 따로 만들어 관리하는게 좋아보입니다!
public Lotto(List<Integer> numbers) { | ||
validate(numbers); | ||
this.numbers = numbers; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
생성자에서 검증하는 것 좋습니다.
|
||
import java.util.List; | ||
|
||
public class LottoResultChecker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로또 결과 체크하는 사람이 따로 필요할까요?
제 생각은 너무 책임이 분배되어 보입니다.
로또 티켓과 같은 부분으로 넣으면 어떨까요?
@@ -0,0 +1,18 @@ | |||
package model; | |||
|
|||
public class LottoService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이것도 마찬가지로 너무 책임이 분배되어 보입니다.
List<Integer> winningNumList = new ArrayList<>(); | ||
for (String num : winningNums) winningNumList.add(Integer.parseInt(num)); | ||
return winningNumList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 파싱과 같은 경우는 모델에서 처리하는게 좋아보입니다!
import java.text.DecimalFormat; | ||
|
||
public class OutputView { | ||
public void printLottos(LottoTickets hadLottos) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view가 모델 내부를 알고있으면 안됩니다.
MVC 설계에서 View는 Model을 알면 안 되고, Model은 View를 알면 안 됩니다!
DTO를 활용해서 해보시는건 어떨까요??
public class OutputView { | ||
public void printLottos(LottoTickets hadLottos) { | ||
System.out.println(hadLottos.size() + "개를 구매하셨습니다!"); | ||
System.out.println(hadLottos); | ||
} | ||
|
||
public void printErrorMessage(String message) { | ||
System.out.println(message); | ||
} | ||
|
||
public void printResult(int[] result, int purchasedPrice) { | ||
System.out.println("당첨 통계"); | ||
System.out.println("----------"); | ||
double totalPrice = 0; | ||
LottoRank[] allRanks = LottoRank.values(); | ||
|
||
for (int i = allRanks.length - 1; i >= 0; i--) { // | ||
LottoRank rank = allRanks[i]; | ||
if (rank == LottoRank.MISS) { | ||
continue; | ||
} | ||
String matchRank = this.getMatchRank(rank); | ||
String prize = this.getPrize(rank.getPrize()); | ||
int count = result[rank.ordinal()]; | ||
totalPrice = totalPrice + ((double) count * rank.getPrize()); | ||
System.out.printf("%s (%s) - %d개\n", matchRank, prize, count); | ||
} | ||
double totalYield = totalPrice / purchasedPrice; | ||
double percentageYield = totalYield * 100; | ||
|
||
System.out.println("총 수익률은 " + String.format("%.1f", percentageYield) + "%입니다."); | ||
} | ||
private String getMatchRank(LottoRank rank) { | ||
String base = rank.getMatchCount() + "개 일치"; | ||
if (rank.isMatchBonus()) { | ||
return base + ", 보너스 볼 일치"; | ||
} | ||
return base; | ||
} | ||
|
||
private String getPrize(int prize) { | ||
DecimalFormat df = new DecimalFormat("###,###"); | ||
return df.format(prize) + "원"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view 임에도 불구하고 로직이 너무 복잡합니다.
MVC 에대한 공부를 조금 더 하시면 좋을 것 같아요!
No description provided.