인프런 커뮤니티 질문&답변

하성철님의 프로필 이미지
하성철

작성한 질문수

스프링 핵심 원리 - 기본편

'관심사의 분리'에서 별개의 memberrepository인스턴스

작성

·

130

0

'관심사의 분리' 강의에서 아래와 같이 MemoryMemberRepository인스턴스를 따로 만들었는데

테스트가 통과하는 이유를 모르겠습니다.

멤버에 join해도 OrderService내의  memberrepository에는 안들어올테고,

할인이 제대로 처리 안돼야 정상일듯 해서요.

답변 1

1

안녕하세요 하성철님!

.

우선 클래스 생성자를 말씀드리겠습니다. 생성자란 어떤 객체가 생성될 때 (예) new OrderServiceImpm() 할 때 등등) 무조건 한번 가장먼저 실행되는 코드입니다. 생성자는 일반 메서드와는 달리 반환타입(return type)이라는 것을 가지고 있지 않고, 메서드 이름이 클래스 이름과 동일하다는 특징이 있습니다.

  class OrderServiceImpl implements OrderService {

    .... 생략 ...

    // 생성자!
    public OrderServiceImpl() {

    }

    // 또 다른 생성자, 생성자 오버라이딩
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.disocuntPolicy = discountPolicy;
    }

    // 얘는 그냥 메서드. 반환타입인 void 가 들어있고, 함수명이 소문자로 시작합니다.
    public void printHello() {
        System.out.println("Hello");
    }
}

이제 아래의 코드를 설명하겠습니다. AppConfig 를 ### 1과 같이  생성하고 config.orderService() 호출하는 순간 ### 2가 실행됩니다.

.

### 2의 코드는 (강의와 다르게 조금 풀어서 작성하였습니다) MemberRepository와 DiscountPolicy를 생성(new)한 다음, OrderServiceImpl() 의 생성자에 전달하고 있습니다.

.

그럼 ###3 처럼 OrderServiceImpl()의 생성자가 실행되며  AppConfig에서 넘겨준 MemberRepository와 DiscountPolicy를 자신이 사용할 수 있도록 손에 쥐고 있게 됩니다. 이처럼 외부에서 OrderServiceImpl이 사용해야할 객체를 주입해주는것을 '의존성 주입' 이라고 합니다. 특히 생성자를 통해 의존성을 주입하는 것을 '생성자 주입'이라고 합니다.

.

이렇게 되면 OrderServiceImple 에서 MemberRepository와 DiscountPolicy를 자신의 것처럼 사용할 수 있습니다. AppConfig를 만들기 전 OrderServiceImpl 내부에서 직접 new 키워드를 사용해 MemberRepository와 DiscountPolicy를 생성했던것과 결과적으로 같습니다.

.

그러나! OrderServiceImpl 내부에서 직접 MemberRepository와 DiscountPolicy를 생성하는가, 외부에서 생성한 뒤 OrderServiceImpl에 전달하여 사용하는가 라는 차이가 있습니다. 이런 방법의 차이가 후에 애플리케이션을 확장할 때 큰 차이를 만들게 됩니다.

### 1
AppConfig config = new AppConfig();
OrderService orderService  config.orderService();

### 2
class AppConfig {
  public OrderService orderService() {
    MemberRepository memberRepository = new MemberMemberRepository();
    DiscountPolicy discountPolicy = new FixedDiscountPolicy();
    return new OrderServiceImpl(memberRepository, discountPolicy);
  }
}

### 3
class OrderServiceImpl extends OrderService {

  private final MemberRepository memberRepository;
  private final DiscountPolicy discountPolicy;

  public OrderServiceImpl(MemberRepository memberRepository,DiscountPolicy discountPolicy) {
     this.memberRepository = memberRepository;
     this.discountPolicy = discoutPolicy;
  }
}

위와 같은 상황에서 이제 OrderService를 이용하기 위해 아래와 같이 작성합니다.  애플리케이션에 변화가 생겼다면 이제 나머지 코드들은 건드리지 않고 AppConfig의 memberService()와 orderService()부분만 수정하면 됩니다.

AppConfig config = new AppConfig();
MemberService memberService = config.memberService();
OrderService orderService = config.orderService();

혹시 이해가 안되는 부분이 더 있으시면 댓글 남겨주시기 바랍니다.

감사합니다.

하성철님의 프로필 이미지
하성철
질문자

강의 자료 내의 코드를 다시 보니 아래와 같이 store가 static이었네요.

그래서 OrderService와 MemberService의 MemoryMemberRepository인스턴스가 서로 달라도 동작하는거였네요. 

public class MemoryMemberRepository implements MemberRepository {
 private static Map<Long, Member> store = new HashMap<>();

강의중엔 빨리 지나가서 저 부분을 놓쳤던 것 같습니다

안녕하세요! 하성철님.

질문하신 내용을 이제 명확히 이해했습니다. :)

네 말씀하신대로 static 한 변수와 메서드는 MemberRepository 클래스에 속하기에

new 로 생성한 인스턴스끼리 공통으로 사용할 수 있습니다.

.

감사합니다.

하성철님의 프로필 이미지
하성철

작성한 질문수

질문하기