안녕하세요, Brad입니다. 오늘은 step3 피드백 받았던 것 마무리했었는데요. 어제 반영한 피드백 내용과 함께 오늘 반영한 DIP 적용(?!) 시도도 기록해볼게요!
우선 어제 받았던 피드백은 다음과 같습니다.
Main
클래스의 업무 과다rank.getWinningMoney()
사용을 피하기 →getter()
사용 피하기Lotto
번호를Integer
대신LottoNum
처럼 추상화하기 → VO만들어 적용해보기LottoGame
에 DIP원칙 적용해보기
하나씩 살펴보죠.
Main 클래스의 업무 과다
Main
클래스에 많은 코드가 담기게 된 이유는 Domain 로직 내 예외를 던져 Main
에서 예외처리를 하기 때문입니다. 그래서 control 패키지 내에 기능별로 클래스를 분리하였습니다. 세부적으로 다음과 같습니다.
- 예외처리하는 부분(입력금액, 수동로또 개수, 1등 로또 번호 등)을 Control 패키지 내에서 클래스로 모두 분리
- 상태값이 들어있는 것이 아니기 때문에 클래스 메서드로 모두 선언
rank.getWinningMoney() 사용 피하기
이 부분은 getter()
메서드를 사용하였기 때문에 다른 방법을 사용하기를 추천한다고 생각하였습니다.
객체지향적으로
Rank
에게 최대한 메시지을 보냄rank
를 매개변수로 보내 반복문 돌리며 그rank
에 맞는 상금을 반환
Lotto 번호 추상화하기
예전에 '좌표계산기' 미션을 진행할 때 x값, y값을 추상화 했었는데요. Lotto
번호도 Integer
대신 LottoNum
과 같이 추상화, 즉 VO를 만들어라는 것입니다. 로또 내 각각의 수까지 추상화할 생각은 미처 하지 못했는데요. 추상화 작업을 진행하면서 어떤게 변화될 수 있는지 간략하게 정리해보았습니다.
- 좀 더 객체지향적인 프로그래밍이란게 확연하게 드러남 → 추상화 객체에 메세지 전달하여 요청 처리
- 각각의 로또 수를 추상화 함으로써 로또 내에서 하나하나 반복문 돌려 예외처리 확인하던 것을 로또 수 추상화한 것에 위임 가능
DIP 적용하기
어제 저녁부터 많이 고민했던 내용이고 아직도 사실 오늘 구현한 내용이 DIP에 맞는 것인지 모르겠습니다. 사실 그냥 시도하지 않고 넘어갈까 생각도 했었는데 제가 생각하던 것 무엇이든 시도하는게 좋을 것 같았어요. 그래서 외국 사이트를 참고해가면서 적용하려 노력했습니다.
제가 생각하는 DIP는 이용하려는 클래스가 이용되는 클래스(구체적인 것)에 의존하지 않고 이 두 클래스 사이에 인터페이스 혹은 추상클래스를 두어 그것에 의존하게끔 하도록 하는 것입니다. 이렇게 된다면 이용되는 클래스가 여러 개가 될 경우 관계없이 사이의 매개인 추상 클래스 또는 인터페이스를 이용하기 때문에 변화에 영향을 받지 않습니다.
이와같은 생각을 바탕에 두고 LottoMachineAbstract
추상클래스와 Automaticall
, Manually
와 같은 인터페이스를 만들었습니다. 로또를 자동으로 생성하는 것은 둘 다 공통이기 때문에 LottoMachineAbstract
에 넣고 구현하였으며, 수동으로 생성하는 것은 MixLottoMachine
에서 구현하였습니다. 위 구조대로 하면 다음과 같이 선언 가능합니다.
public LottoDto generateLottos(int lottoTicketNum, int manualLottoTicketCount) {
LottoMachineAbstract lottoMachine;
if (manualLottoTicketCount == 0) {
lottoMachine = new AutoLottoMachine(lottoTicketNum - manualLottoTicketCount);
return new LottoDto(lottoMachine.getLottos());
}
int autoLottoCount = lottoTicketNum - manualLottoTicketCount;
lottoMachine = new MixLottoMachine(autoLottoCount, manualLottoTicketCount);
return new LottoDto(lottoMachine.getLottos());
}
LottoMachineAbstract
에 getLottos()
추상메서드를 선언해두고 그 하위 클래스에서 각각 로또 머신 성격에 맞게 로또를 만들어준 후 List<Lotto>
객체를 반환하였습니다.
이렇게 구성하면 뭐가 좋을까?
LottoGame
내에List<Lotto>
인스턴스 변수가 없어졌습니다- 이렇게 구성을 하면 메서드의 매개변수로 데이터값을 전달할 수 있기 때문에 테스트를 진행하기가 더 수월해졌습니다.
LottoMachineAbstract
의 하위 클래스로 또 다른 종류의 Lotto Machine이 생겼을 때lottoMachin
객체참조변수를 그대로 이용하여 로또 데이터들을 받을 수 있습니다.getLottos()
추상클래스를 강제로 구현하게끔 하므로 적어도 이 메서드를 새로 만든 클래스에서 사용가능합니다.
인터페이스의 경우 각 성격에 맞게
implements
받은 후 구현을 강제하게끔하여 Lotto Machine이 각 성격에 맞게 제대로 작동하게끔 한다
사실 이렇게 DIP 설계를 하는게 맞는 것인지 아직 확신이 안서네요. 이 부분은 더 많은 객체지향 설계 연습과 구현을 통해 깨달음이 올거라 생각합니다!
오늘 추가적으로 공부한 부분
'TIL' 카테고리의 다른 글
Today's Dev Notes(2018-11-04) (0) | 2018.11.04 |
---|---|
Today's Dev Notes(2018-11-01) (0) | 2018.11.01 |
Today's Dev Notes(2018-10-30) (0) | 2018.10.31 |
Today's Dev Notes(2018-10-28) (0) | 2018.10.29 |
Today's Dev Notes(2018-10-25) (0) | 2018.10.25 |