스프링기본5_AppConfig를 통한 관심사의 분리

하도야지·2021년 6월 25일
0

Spring

목록 보기
5/12

(1) 관심사의 분리

  1. "무엇이 문제인가?"

-> 공연(애플리케이션)에서 실제 배역에 맞는 배우(인터페이스)를 선택하는 것은 누구인가?
--> 로미오 역할을 누가할지는 배우가 정하는 것이 아니다.
--> 이전 코드는 로미오 역할(인터페이스)를 하는 디카프리오 배우(구현체)가 줄리엣역할(인터페이스)를 하는 여자주인공(구현체)를 직접 초빙하고 있음
---> 즉 디카프리오(구현체)가 공연,주인공초빙 등 "다양한 책임" 가지고 있음

  1. "관심사를 분리하자"

-> 배우(구현체)는 본인의 역할 배역 수행에만 집중해야 함.
--> 공연을 구성하고, 담당 배우를 섭외하고, 역할에 맞는 배우를 지정하는 책임을 담당하는 "공연 기획자"가 필요하다.
--->공연 기획자를 만들고, 배우와 공연 기획자의 책임을 확실히 분리하자


(2) AppConfig 생성

  1. 애플리케이션의 전체 동작 방식을 구성(config)하기 위해, "구현객체"를 생성하고, "연결"하는 책임을 가지는 별도의 설정 클래스
  1. AppConfig.java
package springbasic.core;

import springbasic.core.discount.FixDiscountPolicy;
import springbasic.core.member.MemberService;
import springbasic.core.member.MemberServiceImpl;
import springbasic.core.member.MemoryMemberRepository;
import springbasic.core.order.OrderService;
import springbasic.core.order.OrderServiceImpl;

public class AppConfig {
    //생성자주입
    public MemberService memberService(){
        return new MemberServiceImpl(new MemoryMemberRepository());
    }

    public OrderService orderService(){
        return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
    }

}
  • AppConfig는 애플리케이션의 실제 동작에 필요한 "구현객체를 생성"
    -MemberServiceImpl
    -MemoryMemberRepository
    -OrderServiceImpl
    -FixDiscountPolicy
  • AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 "생성자를 통해서 주입"해준다.
    -MemberServiceImpl -> MemoryMemberRepository
    -OrderServiceImpl -> MemoryMemberRepository, FixDiscountPolicy
  1. MemberServiceImpl.java - 생성자 주입

    -> 더이상 MemberServiceImpl은 MemoryMemberRepository(구현체)에 의존 하지 않는다.
    --> 오직 MemberRepository에만 의존한다.
    --> MemberServiceImpl 입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될 지) 알수 없음
    --> MemberServiceImpl의 생성자를 통해서 어떤 구현객체를 주입할 지는 AppConfig에서 결정
    --> MemberServiceImpl은 의존관계에 대한 고민은 AppConfig에 맡기고 실행에만 집중함.


    의존성 주입!! " 외부에서 의존관계를 주입해주는것과 같음"

  2. OrderServiceImpl.java - 생성자 주입

    -> 더이상 OrderServiceImpl FixDiscountPolicy(구현체)에 의존 하지 않는다.
    --> 오직 DiscountRepository에만 의존한다.
    --> OrderServiceImpl 입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될 지) 알수 없음
    --> OrderServiceImpl 생성자를 통해서 어떤 구현객체를 주입할 지는 AppConfig에서 결정
    --> OrderServiceImpl 의존관계에 대한 고민은 AppConfig에 맡기고 실행에만 집중함.


(3) AppConfig 반영 수정

  • OrderApp.java
  • MemberApp.java
  • OrderServiceTest.java
  • MemberServiceTest.java

(4) 정리

  • AppConfig를 통해 관심사를 확실하게 분리함
  • AppConfig는 공연기획자
  • AppConfig는 구체클래스를 선택, 담당배우를 선택, 애플리케이션이 어떻게 동작해야 할지 전체 구성을 책임짐
  • 이제 각 구현체들은 담당 기능을 실행하는 책임만 지면 됨

(5) AppConfig 리팩토링

  1. 리펙토링 이유
  • 현재 AppConfig를 보면 중복이 있고, 역할에 따른 구현이 잘 안보임
  1. 리펙토링 전 AppConfig.java

  2. 리펙토링 후 AppConfig.java

  • new MemoryMemberRepository() 부분의 중복이 제거됨.
    -> MemoryMemberRepository() 변경 시 한 부분만 변경하면 됨
  • AppConfig를 보면 역할클래스와 구현클래스가 한 눈에 보임.
    -> 애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악할 수 있음.

(6) 새로운 구조와 할인 정책 적용

  • 정액(Fix)할인정책을 정률(Rate)할인정책으로 변경하고자 함
  • 어떤 부분만 변경하면 될까?
    ->AppConfig.java만 교체하면 된다.

  • AppConfig.java 변경

  • AppConfig에서 할인정책역할을 담당하는 구현부를 Fix -> Rate 객체로 변경함
  • 이제 할인정책 변경 시, 애플리케이션 구성 역할을 담당하는 AppConfig만 변경하면 됨.
    -> OrderServiceImpl 등 사용영역의 어떤 코드도 변경할 필요 없음
  • 구성영역(AppConfig)는 당연히 변경됨.

**(7) 좋은 객체 지향 설계의 5가지 원칙 적용 확인

**

1. SRP 단일책임 원칙 : 한 클래스는 하나의 책임만 가져야 한다.

  • 클라이언트 객체(MemberServiceImpl, OrderServiceImpl)는 직접 구현 객체를 생성하고, 연결하고, 실행하는 다양한 책임을 가지고 있었다.
  • SRP 단일 책임 원칙에 의해 관심사를 분리함.
  • 구현 객체(AppConfig)를 생성하고 연결하는 책임을 담당함.
  • 클라이언트 객체(MemberServiceImpl, OrderServiceImpl)는 실행하는 책임만 담당

2. DIP 의존관계 역전 원칙: 프로그래머는 " 추상화에 의존해하고 구체화에 의존하면 안됨", 의존성 주입은 이 원칙을 따르는 방법 중 하나이다

  • 새로운 할인 정책을 개발하고, 적용하려고 하니 크라이언트 코드도 변경해야했음.
    -> 클라이언트(OrderServiceImpl)가 추상(DiscountPolicy)과 구현체(FixDiscountPolicy) 모두에 의존하고있었기 떄문.
  • 클라이언트 코드가 추상(DisCountPolicy)에만 의존하도록 변경
  • AppConfig에서 객체 인스턴스(FixDiscountPolicy)를 대신 생성하여 클라이언트 코드에 의존관계를 주입해줌

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

  • 다형성 사용하고 클라이언트가 DIP 지킴
  • 애플리케이션을 사용 영역과 구성 영역으로 나눔
  • 구성영역(AppConfig)에서 의존관계(Fix->Rate)를 변경하여 클라이언트에 주입하므로, 클라이언트 코드는 변경하지 않아도 됨.
  • 소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있음
profile
프로그래머를 꿈꾸는 코더

0개의 댓글

관련 채용 정보