본문 바로가기
백엔드개발자/SPRING, JPA 등...

AppConfig 와 의존성 주입, 구현체가 아닌 추상화에만 의존

by 보혀니 2022. 1. 3.

.

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 를 통해서 함

 

 

 

 

 

 

이전코드

 

 

수정코드

 

 

 

 

 

 

 

 

서비스테스트 클래스도 수정해야 한다.

 

왜 비포이치 써야하는지 아직 모르겠음.