안녕하세요, Brad입니다. 오늘은 수업시간에 DIP(Dependency Inversion Principle)에 대해서 배웠는데요. 이에 대해서 간략하게 정리해볼께요.
먼저 의존성 역전 법칙(DIP)는 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는 위계관계를 끊는 것을 의미합니다. 구체적인 것에 의존하는 것을 인터페이스로 바꾸고, 기존 의존받던 것도 그 인터페이스에 의존 받도록 바꾸는 것입니다.
위와 같이 기존에는 LottoGame
내에서 생성자를 Money
로 받아 그 Money
로 AutoLottoGenerator
에 넣음으로써 로또를 생성하였습니다. 로또를 자동으로만 생성해주는 부분에 의존하고 있는 것이죠.
만약 수동과 혼합으로 로또를 생성하고 싶다면 어떻게 될까요?
만약 요구사항의 변경을 예상한다면 이런 경우도 고려할 수 있죠. 그렇게 된다면 LottoGame
이 AutoLottoGenerator
이 아니라 혼합으로 로또를 생성하는 곳으로 의존관계가 바뀔 것입니다. '하위 레벨 모듈의 변경에 맞게 의존 관계를 맺게 할 수는 없을까?' 이를 고려한다면 다음과 같이 리팩토링할 수 있습니다.
이렇게 된다면 기존에 LottoGame
생성자의 매개변수로 Money
받던 것을 인터페이스로 받습니다. 이 인터페이스는 받기 전 AutoLottoGenerator
또는 혼합_로또_생성
클래스로 구현되었기 때문에 각 성격에 따른 로또 생성기를 받을 수 있습니다.
이렇게 리팩토링을 하면서 재미있었던 점은 인터페이스를 매개변수로 넘긴다는 것입니다. 이렇게 인터페이스를 넘기면 로또 생성기가 필요한 부분에서 인터페이스를 이용하고, 로또 생성기 성격이 바뀌더라도 카멜레온처럼 변화에 대응할 수 있는 것입니다. 이렇게 인터페이스로 만들었기 때문에 LottoGame
내에서 List<Lotto> lottos
를 인스턴스 변수로 만들 필요가 없었으며 결국 테스트할 때도 인터페이스 반환 값을 저희가 만든 테스트 데이터로 바꿈으로써 LottoGame
을 테스트할 수 있었습니다.
인터페이스를 테스트코드 내에서 사용하기 위해 다음과 같이 구현할 수 있습니다.
class FakeLottoGame implements LottosGenerator{
@Override
public List<Lotto> generate(Money money) {
return createTestLottos();
}
}
이렇게 저희가 만든 로또 데이터들(createTestLottos()
)을 넘겨줄 인터페이스를 구현하는 가짜로또게임(FakeLottoGame
)을 만듭니다.
LottoGame lottoGame = new LottoGame(new FakeLottoGame());
그리고 이 FakeLottoGame
객체를 LottoGame
으로 보내주는거죠. 이렇게 되면 LottoGame
내의 LottoGenerator
객체참조변수가 generate()
메서드를 이용하여 수동으로 테스트로 만든 로또 데이터들을 List<Lotto> lottos
에 담을 수 있을 것입니다. 그런데 굳이 테스트를 위한 것인데 Inner Class나 따로 클래스를 밖에서 만들 필요는 없죠. 우선 익명 클래스로 바꿀 수 있습니다.
LottoGame lottoGame = new LottoGame(new LottosGenerator() {
@Override
public List<Lotto> generate(Money money) {
return createTestLottos();
}
});
그리고 LottosGenerator
라는 인터페이스에 메서드가 하나만 선언되어 있다면 람다를 이용하여 다음과 같이 줄일 수 있는 것이죠.
LottoGame lottoGame = new LottoGame(money -> createTestLottos());
DIP원칙을 왜 사용하면 좋은지, 어떻게 활용될 수 있는지, 의존 관계가 더 많아지면 어떻게 설계할건지.. 이 부분들은 연습하면서 깨달아야 할 것 같네요.
오늘 추가적으로 공부한 부분
'TIL' 카테고리의 다른 글
Today's Dev Notes(2018-11-12) (0) | 2018.11.13 |
---|---|
Today's Dev Notes(2018-11-04) (0) | 2018.11.04 |
Today's Dev Notes(2018-10-31) (0) | 2018.10.31 |
Today's Dev Notes(2018-10-30) (0) | 2018.10.31 |
Today's Dev Notes(2018-10-28) (0) | 2018.10.29 |