생성자 주입 전
OrderServiceImpl.java
public class OrderServiceImpl implements OrderService{
MemberRepository memberRepository = new MemoryMemberRepository(); // DIP 위반!
@Override
public Order createOrder(Long memberId) {
Member orderMember = memberRepository.findById(memberId);
...
}
}
OrderServiceImpl이 MemberRepository(인터페이스) 뿐만 아니라 구현체인 MemoryMemberRepository에도 의존하고 있습니다.
만약 구현체를 MemoryMemberRepository에서 다른 구현체로 변경할 때면 OrderServiceImpl클래스에서도 변경해야 하기 때문에 OCP도 위반하게 됩니다.
생성자 주입 후
OrderServiceImpl.java
public class OrderServiceImpl implements OrderService{
MemberRepository memberRepository;
public OrderServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member orderMember = memberRepository.findById(memberId);
...
}
}
이렇게 생성자를 통해서 구현체를 주입받게 하면 OrderServiceImpl은 구현체를 알 수 없고,
MemoryMemberRepository(구현체)가 아닌 MemberRepository 인터페이스에만 의존하게 됩니다.
이렇게 OrderServiceImpl에서 의존관계를 외부로부터 주입받는걸 DI(의존관계 주입 or 의존성 주입)라고 합니다.
위 코드는 그 중에서도 생성자 주입입니다.
AppConfig.java
public class AppConfig {
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
);
}
}
AppConfig가 실제 구현체를 생성하도록 했습니다.
orderService() -> new OrderServiceImpl
-> OrderServiceImpl.java의 생성자 memberRepository 파라미터에 MemoryMemberRepository가 주입됩니다.
테스트
class OrderServiceTest {
MemberService memberService;
OrderService orderService;
@BeforeEach // 테스트 시작하기 전에 실행되는 애노테이션
public void beforeEach(){
AppConfig appConfig = new AppConfig(); // AppConfig 객체 생성
orderService = appConfig.orderService(); // 여기서 실행해서 의존성 주입!
}
@Test
@DisplayName("오더 서비스 테스트")
void orderTest(){
long memberId = 1L;
Member member = new Member(memberId, "홍길동", Grade.BRONZE);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
...
}
}
orderService.createOrder()는 OrderServiceImpl.java처럼 memberRepository의 함수 등 실행해야 하기 때문에 구현체가 필요합니다. (구현체가 주입되지 않으면 NPE가 발생합니다)
생성자 주입으로 MemoryRepository가 주입되어서 위 테스트에서는 성공합니다
결과
OrderServiceImpl은 인터페이스인 memberRepository에만 의존하며 구현체를 몰라도 됩니다. DIP!
구현체인 MemoryMemberRepository말고 다른 구현체로 변경해도 OrderServiceImpl에서는 바꿀 코드가 없습니다. OCP!
'Spring' 카테고리의 다른 글
[tomcat] error running tomcat can't find catalina.jar (1) | 2024.07.23 |
---|---|
[Spring Boot] JPA @Transactional과 변경 감지 Update (0) | 2024.07.11 |
[SpringBoot] 프로젝트 빌드 및 실행 (0) | 2023.10.17 |
[SpringBoot/Thymeleaf] ajax 회원가입 중복체크 2 (0) | 2022.06.28 |
[SpringBoot/Thymeleaf] ajax 회원가입 중복체크 (Spring Data JPA) (0) | 2022.06.28 |