인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

작성자 없음

작성자 정보가 삭제된 글입니다.

스프링 핵심 원리 - 기본편

IoC, DI, 그리고 컨테이너

강의 듣고 따로 공부하고 있는데 DIP와 리팩터링 관련 제가 학습한 지식이 맞는 걸까요?

작성

·

324

1

스프링 부트 : DIP(의존 관계 역전 원칙)


public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();

    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
  • MemberServiceImpl을 보면 private final MemberRepository memberRepository = new MemoryMemberRepository(); 를 통해 추상화와 구현체를 관리하고 있다.
  • 만약 요구사항 변경으로 새로운 구현체로 변경해 줘야 한다면 = new MemoryMemberRepository(); 이 부분에 대한 수정이 필요해진다.
  • MemberServiceImpl에서 추상화를 통해 구현체를 관리하고 구현체에 대한 변경이 있을 때 인터페이스를 통해서만 구현체를 변경할 수 있어야 하는데 지금 보면 인터페이스가 아닌 MemberServiceImpl에서 코드 수정이 일어난다.
  • 결국 지금 이 코드는 객체 지향 5가지 원칙 중 DIP*(Dependency Inversion Principle | 의존 관계 역전 원칙)*에 위반된다.
public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }
}
  • 해결을 위해 AppConfig 클래스를 만들어 이런 구현체들을 관리해 준다.
    • 생성과 연결을 담당한다.
  • return new MemberServiceImpl(new MemoryMemberRepository()); 코드로 구현 객체를 생성한다.
  • 간단히 해석하자면 MemberServiceImpl을 만들고 내가 만든 MemberServiceImplMemoryMemberRepository를 사용할거야.!” 와 같이 해석할 수 있다.
public class MemberServiceImpl implements MemberService {ㅗ

    private final MemberRepository memberRepository;

    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
  • public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } 생성자를 통해 받아준다.
  • 이렇게 따로 설정 클래스에서 구현체를 받아 생성자를 통해 추상화와 구체화를 분리해 주는 것을 생성자 주입이라고 한다.
  • AppConfig 클래스에서는 결국 실제 동작에 필요한 구현 객체를 생성하게 된다.
  • AppConfig 클래스는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해 주입(연결)해준다.
  • 결국 AppConfig 객체는 객체를 생성하고 생성한 객체를 생성자로 전달하는 행위를 하게 되고 이런 행위를 DI(Dependency Injection)라고 한다.( 의존관계 주입)
  • 결과적으로는 MemberServiceImpl 클래스는 인터페이스에만 의존하게 되고 구체적인 구현 클래스에 대해 전혀 의존하지 않게 되므로 DIP를 잘 지키는 코드가 된다.
MemberService memberService;

    @BeforeEach
    public void beforEach() {
        AppConfig appConfig = new AppConfig();
        memberService = appConfig.memberService();
    }
    //MemberService memberService = new MemberServiceImpl(memberRepository);
  • @BeforeEach 는 각 테스트를 실행하기 전에 무조건 실행시켜준다.
  • 마지막으로 테스트 코드 또한 바꿔주고 테스트 전체 실행을 해주면
    • 성공적으로 DIP 보안을 마치게 된다.

      Untitled

코드 리팩터링


public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }
}
  • 이 코드는 객체 안에서 new를 통해 특정 객체를 직접 생성하고 있다.
  • 이러면 문제가 중복이 생긴다.
  • 예를 들면 MemberServiceImplOrderServiceImpl에서 MemoryMemberRepository를 사용하기 위해 각각 위 코드처럼 (new MemoryMemberRepository()); 이렇게 따로 생성해 줘야 하기 때문에 이 자체를 중복이라고 본다.
public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    private MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

}
  • 리팩터링 후에는 memberRepository()new MemoryMemberRepository()를 생성하고 MemberServiceImpl과 코드엔 없지만 OrderServiceImpl에서 따로 new를 통해 생성하지 않고 memberRepository()를 통해 객체를 생성한 것을 불러와 사용하게 되어 전체적으로 객체 생성 행위는 줄어든 것이므로 중복을 피했다보고 이러면 DIP에 이어 OCP도 만족하게 된다.

  • DIP / OCP 참고

    • DIP

      • 의존 관계 역전 원칙
        • 구체적인 것이 추상화에 의존해야 한다.
        • 고차원 모듈은 저차원 모듈에 의존하면 안 되고 추상화된 것에 의존해야 한다.
    • OCP

      • 개방 - 폐쇄 원칙
        • 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다.
        • 확장에 대해 열려 있어야 하고 수정에 대해 닫혀 있어야 한다.

제어의 역전


Untitled

  • 예를 들면 JUnit이 있다.
  • 테스트 코드를 작성하면 JUnit에서 로직은 코딩했지만 실행과 제어에 대한 권한은 JUnit이라는 Test Framework이가져가 이것을 대신 실행해 준다.
  • 자신만의 Life Cycle 속에서 규칙을 통해(@BeforeEach를 먼저 실행하고 @Test를 실행한다. 등) 내가 작성한 코드를 Call back식으로 불러지게 된다.
  • 내가 코드만 개발하면 프레임워크에서 딱 필요에 따라 적절하게 호출하는 것, 호출하는 제어권을 넘기는 것을 제어의 역전이라고 한다.

라이브러리


  • 내가 작성한 코드가 직접 제어의 흐름을 담당하면 라이브러리이다.
  • 자바 객체를 직접 xml이나 json으로 바꾼다면 이것은 라이브러리이다.

답변 1

2

안녕하세요. wogxmiw님, 공식 서포터즈 David입니다.

강의와 관련하여 궁금하신 부분을 잘 요약하여 질문해주시면 감사하겠습니다:)

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기