ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 예제에 객체 지향 원리 적용해보기
    BackEnd/Spring 2022. 7. 27. 21:10

    앞서 만든 예제는 client 코드가 구체클래스, 인터페이스 모두에 의존함!

    그래서 구체클래스를 변경할 때 클라이언트도 함계 변경해서 DIP를 위반함

    역할과 구현을 제대로 나눴다고 보기 어려움

    DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경하자

    아래처럼 구체적인 RateDiscountPolicy() 정의하는 코드를 없애자

    이 상태에서는 null pointer exception 발생함

    누군가가 이 클라이언트 orderServiceImpl 객체에 DiscountPolicy의 구현 클래스를 주입시켜줘야함


    AppConfig

    : 애플리케이션의 전체 동작 방식을 구성(config)하기 위해, 구현 객체를 생성하고 연결하는 책임을 가지는

    별도의 설정 클래스

     

     

    1) 구현 객체를 생성함

     

    2) 생성자를 통해서 주입함(연결)

    - 인터페이스 선언만 해놓고 실체 구현체는 생성자로 받음

    - MemoryMemberRepository를 의존하지 않고 인터페이스만 의존하게됨

    - 어떤 구현객체가 들어올지 모르고 어떤 객체를 주입할지는 오직 AppConfig에서만 결정됨

     

    MemberServiceImpl 구현 클래스

     

     

    - 이로써 관심사가 분리되었음 -> 역할과 구현이 분리됨

    - appConfig 객체는 memoryMemberRepository 객체를 생성하고 그 참조값을 memberServiceImpl을 생성하면서 생성자로 전달함

    - impl 입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 : DI(Dependency Injection) - 의존성 주입

     

    OrderServiceImpl 구현 클래스

     

    - 설계 변경으로 더이상 impl 객체가 fixdiscountPolicy를 의존하지 않음 -> 인터페이스만 의존


     

    AppConfig 실행


    AppConfig 리팩터링

     

    - 각 impl에 new MemoryMemberRepository()가 두번 선언되어 있음 -> 중복

    - 리팩토링을 이용하여 중복을 제거해보자 

    - ctrl + m을 누르면 인텔리제이에서 리팩토링 기능을 수행해줌(window)

    리팩토링 전

    - 리팩토링으로 중복이 제거되고, 애플리케이션의 전체 구성을 한눈에 확인할 수 있음

    리팩토링 후

    이제 여기서 할인정책을 고정에서(FixDiscouintPolicy) 정률할인 정책으로 바꾸려면 client 객체 바꾸는 일 없이

    AppConfig에서 한줄만 바꾸면 됨


    좋은 객체 지향 설계의 5가지 원칙의 적용

     

    1. SRP 단일 책임 원칙

    : 한 클래스는 하나의 책임만 가져야 한다.

     

    - 이전 클라이언트 코드는 직접 구현 객체를 생성하고, 연결하고 , 실행하는 다양한 책임을 가짐

    - AppConfig가 구현 객체를 생성하고 연결하는 책임, 클라이언트 객체를 실행하는 책임 으로 나눔

     

    2. DIP 의존관계 역전 원칙

    : 의존성 주입 -> 구체화가 아닌 추상화에 의존

     

    - 이전 클라이언트 코드에는 DiscountPolicy 즉, 추상화 인터페이스에만 의존하는 것이 아니라

    구체화 구현 클래스도 함께 의존했음(FixDIscountPolicy, RateDIscountPolicy)

    - AppCofig가 객체를 대신 생성해서 클라이언트 코드에 의존관계를 주입한다.

     

    3. OCP

    : 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.

     

    - AppConfig가 의존관계를 Fix -> Rate로 변경하고 클라이언트 코드에 주입하면 클라이언트는 변경하지 않은 상태로 

    소프트웨어가 새롭게 확장될 수 있음.

    - 그리고 사용 영역의 변경에는 닫혀있게 됨

     

     


    IoC, DI , 그리고 컨테이너

     

     

    IoC

    - 프로그램에 대한 제어 흐름에 대한 권한은 모두 AppConfig가 가짐

    - 제어의 역전(IoC)란 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것

     

     

    DI

    정적인 클래스 의존 관계

    - 클래스가 사용하는 import 코드만 보고 의존관계 쉽게 판단 가능(애플리케이션 실행x)

    - OrderServiceImpl은 MemberRepository, DiscountPolicy에 의존함 

    하지만 !!! 실제 어떤 객체가 주입될지는 모름

     

    동적인 클래스 의존 관계

    - 애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서

    클라이언트와 서버의 실제 의존관계가 연결 되는 것을 의존관계 주입이라고 함

     

     

    따라서 AppConfig 처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것을 IoC컨테이너 또는 DI컨테이너라고 함

     

     


    스프링으로  전환해보기

     

    - AppConfig에 설정을 구성한다는 뜻의 @Configuration

    - 각 메서드에 @Bean 붙이면 스프링 컨테이너에 스프링 빈으로 등록됨

    AppConfig.class

    - 두 코드를 실행하면 스프링 관련 로그가 실행되면서 기존과 동일한 결과가 출력됨

    MemberApp.class
    OrderApp.class

     

    스프링 컨테이너란?

    - ApplicationContext를 스프링 컨테이너라고 함

    - 이전에는 개발자가 직접 AppConfig 사용해서 DI했음 -> 스프링 컨테이너를 사용하자!

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

    - @Configuration이 붙은 AppConfig를 설정 정보로 사용함

    - @Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록함 -> 이렇게 컨테이너에 등록된

    객체를 스프링 빈이라고 한다.

    - @Bean 이 붙은 메서드의 명 = 스프링 빈의 이름

    - 스프링 빈은 applicationContext.getBean()로 찾을 수 있음

    'BackEnd > Spring' 카테고리의 다른 글

    [Spring] 싱글톤 컨테이너  (0) 2022.08.02
    [Spring] 예제 만들기  (0) 2022.07.22
Designed by Tistory.