.
AppConfig는 애플리케이션의 실제 동작에 필요한 '구현 객체'를 생성한다.
- MemberServiceImp
- MemoryMemberRepository
- OrderServiceImpl
- Rate(Fix)DiscountPolicy ...
AppConfig는 생성한 객체 인스턴스의 참조를 '생성자'를 통해서 주입 해준다.
- MemberServiceImp 같은 경우, new 해서 MemoryMemberRepository 객체를
매개로 해서 MemberRepository의 참조값을 넣어준다는 것!
package com.hello.member;
// 구현체가 하나만 있을 때 *Imp 이라고 관례상 많이 쓴다고 합니다
public class MemberServiceImp implements MemberService{
// new MemberRepository 얘는 인터페이스, 불안전한 객체라 혼자서 사용할 수 없다고, 이미 잘 배웠지
// private final MemberRepository memberRepository = new MemoryMemberRepository();
//
//
// 현재 MmeberServiceImp 에서 MemboryMemberRepository를 지정했다.
// 하지만 ServiceImp이 아닌 AppConfig에서 지정해 줄 것임
// ServiceImp의 역할이 아니었음
// 아래처럼 바꾸기
//
private final MemberRepository memberRepository;
// 생성자를 통해서 memberRepository 구현체가 무엇일지 결정한다....
// 현재 memberRepository에는 MemoryMemberRepository가 타고 와있음.
// !!! MemoryMemberRepository에 대한 코드없이 인터페이스 코드만 있음
// Imp은 추상화에만 의존하게 되었다.
public MemberServiceImp(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
// memberServiceImp 입장에서 보면 의존관계를 마치 외부에서 주입해주는것 같다하여
// 의존관계 주입(의존성 주입)이라고 한다.
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
설계변명으로 MemberServiceImp은 더이상 MemoryMemberRepository를 의존하지 않는다.
단지 MemberRepository 인터페이스에만 의존하게 되었다.
MemberServiceImp 입장에서 생성자를 통해 어떤 구현객체가 주입될지 알 수 없다.
어떤 구현 객체를 주입할지는 오직 외부 'AppConfig' 에서 결정된다.
MemberServiceImp 는 이제부터 의존관게에 대한 고민은 외부에 맡기고
실행에만 집중하면 된다.★
객체의 생성과 연결은 'AppConfig' 가 담당한다.
★ DIP 완성 !!!! ★
MemberServiceImp은 MemberRepository인 추상에만 의존한다.
이제 구체 클래스를 몰라도 된다.
이제 객체를 생성하고 연결하는 역할 / 실행하는 역할이 분리 되었다.
package com.hello.order;
import com.hello.discount.DiscountPolicy;
import com.hello.discount.FixDiscountPolicy;
import com.hello.discount.RateDiscountPolicy;
import com.hello.member.Member;
import com.hello.member.MemberRepository;
import com.hello.member.MemoryMemberRepository;
public class OrderServiceImpl implements OrderService {
// private final MemberRepository memberRepository = new MemoryMemberRepository();\
// private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
// final은 무조건 값이 할당되어야하니까 final을 지우고
// 현재 문제인 구현체에도 의존하는 것을 고치기 위해, 인터페이스에만 의존하도록 코드를 변경시켰다
// 하지만 널포인트 빨간 에러가 남....
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
// 방법. 생성자 주입.
// 이렇게 하여 현재 Impl 클래스에서는 MemberRepository,
// DiscountPolicy 인터페이스의 구현체를 모르게 됨!
// RateDiscountPolicy가 들어올지 FixDiscountPolicy가 들어올지 전혀 모름!!!!
// 그저 주어진 역할대로 로직만 수행 하면 됨 편_안
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
super();
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Override
public Order creatOrder(Long memberId, String itemName, int itemPrice) {
// (주문생성 요청이 오면) 회원 정보 조회
Member member = memberRepository.findById(memberId);
// 할인정책에 회원정보를 넘긴다.
// 등급만 넘겨도되는데 확장성을 위해서 회원정보 자체를 넘겼음
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
이전 코드
수정코드
서비스, 서비스 구현체, 멤버레포지토리, 메모리 멤버레포지토리 이런 순차적인 것이 아니라
AppConfig 를 통해서 함
이전코드
수정코드
서비스테스트 클래스도 수정해야 한다.
왜 비포이치 써야하는지 아직 모르겠음.
'백엔드개발자 > SPRING, JPA 등...' 카테고리의 다른 글
IOC, DI, 제어의역전 (0) | 2022.01.11 |
---|---|
AppConfig 리팩토링 (0) | 2022.01.11 |
정률할인과 테스트 / 할인정책 바꾸기 (0) | 2022.01.03 |
주문과 할인 도메인 실행과 테스트 (0) | 2021.12.28 |
주문과 할인 도메인 설계 (0) | 2021.12.28 |