좋은 객체지향 프로그래밍을 만들기 위해서는 이전에 작성한 역할과 구현의 분리가 첫 번째이며,

객체지향의 원칙 5가지(SOLID)를 지원하기 위해서 스프링에서 컨테이너라는 좋은 기능을 지원한다.

 

DIP(의존 관계 역전)를 지원하기 위해서 추상화를 통해 구현 객체와 분리하며,

분리된 추상화와 구현 객체를 이을 수 있는 방법이 컨테이너이다. 

 

서비스에서는 추상 객체(인터페이스)를 사용하여 클라이언트(서비스/객체 관련 코드)에 변경이 없도록 한다.

이후 AppConfig와 같이 애플리케이션의 구현 객체를 생성하고, 구성하는 역할에 책임을 지는 클래스를 생성하여 사용할 수 있다.

객체에 대한 할당은 생성자 주입을 통해서 진행하며, 아래의 코드와 같이 사용할 수 있다.

 

이러한 역할을 수행하는 것을 IOC 컨테이너 = DI 컨테이너 = 어샘블러 = 오브젝트 팩토리 라고 한다.

IOC(Inversion of Control)은 제어 역전으로 프로그램의 흐름을 외부에서 관리하는 것을 의미한다.

이와 유사하게 DI(Dependency Injection)은 외부에서 객체에 대한 구현을 정하는 것을 의미한다.

예를 들면 결제 서비스에서 멤버 클래스를 호출할 때, DIP에 의해서 추상 클래스로 멤버 인스턴스를 생성하며,

실제 구현 클래스는 IOC(DI) 컨테이너를 통해 구현 클래스의 인스턴스를 생성한다.

 

이러한 IOC 컨테이너를 스프링에서 생성하기 위해서는 몇 가지 규칙이 있으며, 컨테이너 선언 객체와 선언된 컨테이너 사용 객체에 따라 수행해야할 부분이 있다.

 

컨테이너 등록 객체 내 수행 필요사항

  1. 클래스 위에 @Configuration 에너테이션 추가
  2. 각 주입 메서드 마다 @Bean 에너테이션 추가 
  3. 중복을 없게 만들기 위해 추상 객체 단위로 관리하기 위한 리팩토링 수행 
@Configuration
public class AppConfig {

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

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
}

 

 

선언된 컨테이너 사용 객체 내 수행 필요 사항

  1. ApplicationContext 인스턴스 생성 - 스프링 컨테이너로써 등록된 객체를 불러올 수 있으며, 컨테이너 등록 객체 클래스를 인자로 사용
  2. Bean을 통해서 컨테이너에 등록된 객체를 사용 - 스프링 빈은 메서드 명을 key로, 리턴 값을 value로 사용
public class MemberApp {
    public static void main(String[] args) {

//        AppConfig appconfig = new AppConfig();
//        MemberService memberService = appconfig.memberService();
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);


        Member member = new Member(1L, "memberA", Grade.VIP);
        memberService.join(member);

        Member findMember = memberService.findMember(1L);
        System.out.println("new member = " + member.getName());
        System.out.println("findMember = " + findMember.getName());
    }
}

 

+ Recent posts