discount
패키지 아래 DiscountPolicy
interface의 구현체 RateDiscountPolicy
클래스를 생성한다.<코드>
RateDiscountPolicy.java
에서 discount 메소드 이름 위에 커서를 두고 IntelliJ 단축키 Ctrl+Shift+T를 누르면 테스트를 쉽게 생성할 수 있다.Assertions
를 입력하고 Alt+Enter를 이용하면 쉽게 static으로 import 할 수 있다.<코드>
@Test
@DisplayName("VIP가 아니면 할인이 적용되지 않아야 한다.")
void vip_x(){
//given
Member member = new Member(1L, "memberVIP", Grade.BASIC);
int discount = discountPolicy.discount(member,10000);
Assertions.assertThat(discount).isEqualTo(1000);
}
discount
의 값은 0이 되어야 한다.isEqualTo
에 1000을 입력하였기 때문에 테스트 오류가 발생한다.새로 작성한 정률 할인 정책 코드를 적용한다.
order.OrderServiceImpl
의 FixDiscountPolicy()
를 RateDiscountPolicy()
로 변경한다.OrderServiceImpl는 SOILD 원칙에 위반된다.
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
OrderServiceImpl
은 Discountpolicy
인터페이스 뿐만 아니라 FixDiscountPolicy
구현 클래스도 의존하고 있다.OrderServiceImpl
을 수정해야 한다.private DiscountPolicy discountPolicy
로 코드를 변경한다.OrderServiceImpl
에 DiscountPolicy
의 구현 객체를 대신 생성하고 주입해주어야 한다.hello.core
밑에 AppConfig
클래스를 생성한다.<코드>
MemberServiceImpl
를 다음과 같이 수정한다.MemoryMemberRepository()
구현 객체를 직접 만들지 않고 생성자를 통해 만든다. private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository
}
MemberServiceImpl
에 MemoryMemberRepository
는 존재하지 않는다. (의존하지 않는다)MemberRepository
인터페이스만 존재한다.OrderServiceImpl
또한 MemberServiceImpl
와 같은 형식으로 수정한다.public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
public class MemberServiceTest {
MemberService memberService;
@BeforeEach
public void beforeEach(){
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
AppConfig
를 적용한다. @BeforeEach
는 각 @Test
가 실행될 때마다 실행 전에 호출되는 애노테이션이다.AppConfig
를 리팩터링한다.public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy(){
return new FixDiscountPolicy();
}
}
public DiscountPolicy discountPolicy(){
//return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
OrderServiceImpl
등)의 코드는 변경할 필요가 없다.<생략>
FixDiscountPolicy
객체 인스턴트를 클라이언트 코드 대신 생성해서 클라이언트 코드에 의존관계를 주입했다.FixDiscountPolicy
에서 RateDiscountPolicy
로 변경하여 클라이언트에 주입하므로 클라이언트 코드의 변경은 필요하지 않다.OrderServiceImpl
은 필요한 인터페이스들을 호출하지만 어떤 구현 객체들이 실행될 지 모른다.OrderServiceImpl
은 DiscountPolicy
인터페이스에 의존한다. 실제 어떤 구현 객체가 사용될지는 모른다.OrderServiceImpl
은 MemberRepositoy
, DiscountPolicy
에 의존한다는 것을 알 수있다.@configuration
을 추가하고, 객 메소드 위에 @Bean
을 추가한다.<코드>
기존 객체 생성 코드는 주석처리하고, 새로운 코드를 추가한다.
//AppConfig appConfig = new AppConfig();
//MemberService memberService = appConfig.memberService();
//OrderService orderService = appConfig.orderService();
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
ApplicationContext
를 스프링 컨테이너라 한다@Bean
이 적힌 메서드를 모두 호출해서 스프링 컨테이너의 등록한다. 빈의 이름은 메서드명으로 한다.본 포스팅은 김영한 강사의 스프링 핵심 원리 강의를 수강하고 요약한 것으로, 해당 강의의 영상 및 강의자료를 참고하였습니다.