[Spring] 03-3. 새로운 구조와 할인 정책 적용

지찬우·2022년 12월 27일
0

Spring

목록 보기
12/27
post-thumbnail

이 시리즈는 인프런 강의(김영한 님의 ‘스프링 핵심 원리 - 기본편’)로 공부하며 혼자 기록하고, 사람들과도 공유할 수 있도록 작성하는 글이다. 최대한 추가적인 정보는 공식 홈페이지, 문서를 보며 얻을 예정이다.
(개인적인 생각과 이해가 들어가 있기 때문에 저의 ‘무식함’이 있을 수 있습니다😜 혹시라도 이 글을 보게 되시는 분이 계시다면 잘못된 부분 댓글로 많이 알려주시면 너무 감사하겠습니다!!)

GitHub Repository : https://github.com/jcw1031/spring-core-study


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

🔨 AppConfig 리팩터링

지금까지 우리가 만든 AppConfig는 중복되는 부분도 있고, 역할에 따른 구현이 눈에 잘 보이지 않는다. 다시 말해, 역할에 따른 구현을 어떤 구현체가 하는지 한 그림에 확실하게 드러나야 하지만 그렇지 않다는 뜻이다. 그래서 그 부분을 보완하도록 수정해 보자.

MemberService 역할의 구현체는 MemberServiceImpl로 구현한다는 것이 어느 정도 보이지만, MemberRepository 역할의 구현체는 확실하게 보이지 않는다.(new MemoryMemberRepository() 부분) 그래서 그 부분을 메서드로 만들어 주도록 하겠다.


new MemoryMemberRepository를 드래그하고, 아래 단축키를 사용하면 빠르게 메서드를 생성할 수 있다. 단축키를 사용하면 아래와 같은 화면처럼 변하는데, 톱니바퀴 모양을 클릭한 후에 More option 버튼을 클릭한다.

MacOS : + + M
Windows : Ctrl + Alt + M


그럼 Extract Method 창에서 메서드를 세부적으로 설정할 수 있다.


Declare static은 메서드가 static으로 선언되는 것이니 체크를 풀어준다. Name은 memberRepository로 하고 return 타입을 MemberRepository 인터페이스로 해주자! (이 메서드는 외부에서 사용할 것이 아니기 때문에 public으로 선언하지 않아도 된다.) 설정을 마치면 Refactor를 누른다.


그러면 다른 부분에 중복된 부분도 수정할 것인지 물어보는데, Replace 버튼을 눌러 중복된 다른 부분도 변경해 준다.


그럼 아래와 같이 메서드가 생성되고, 두 개의 부분이 메서드를 호출하는 형식으로 변경된 것을 확인할 수 있다.


남은 DiscoutPolicy 역할의 구현체(new FixDiscountPolicy() 부분)도 마찬가지로 메서드로 주입해 주도록 변경한다.


리팩터링 후

리팩터링을 거친 AppConfig는, 메서드를 보면 한눈에 역할에 대한 구현이 잘 보인다.MemberServiceMemberServiceImpl을 사용할 것이다’, ‘MemberRepositoryMemoryMemberRepository를 사용할 것이다.’라는 것이 확실하게 보인다.


이로써 AppConfig에 역할과 구현 클래스가 한눈에 들어온다. 애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악할 수 있는 것이다❗️

🆕 새로운 할인 정책 적용

이제 정액 할인 정책에서 정률 할인 정책으로 변경해 보자. 예전의 코드였다면 클라이언트에서 변경이 일어났겠지만, 우리는 객체를 생성하고 구성하는 AppConfig를 통해 클라이언트에 영향을 주지 않고 변경할 수 있게 되었다. AppConfig 클래스의 코드만 변경하면 되는 것이다!


AppConfigDiscoutPolicy 역할의 구현체를 FixDiscountPolicy에서 RateDiscountPolicy로 변경하면 끝이다. 간단하다.


실행해 보자. 너무 잘 동작한다😃

이로써 OCP와 DIP를 지킬 수 있게 되었다!

📋 흐름 정리

  • 전체 도메인 개발
  • 새로운 할인 정책 개발
  • 새로운 할인 정책 적용 문제점
  • 관심사의 분리
  • AppConfig 리팩터링
  • 새로운 구조와 할인 정책 적용

전체 도메인을 개발하고, 다형성을 사용해 새로운 할인 정책을 개발하는 것까지 아무 문제 없이 잘 진행했다. 하지만 새로운 할인 정책을 적용할 때 ‘클라이언트 객체인 주문 서비스 구현체도 수정’을 해야 하는 문제점이 있었다. 주문 서비스 구현체가 인터페이스인 DiscountPolicy도 의존하고, 구현체인 FixDiscountPolicy도 의존하고 있었다. DIP를 위반한 것이다.

그래서 우리는 이 문제를 해결하기 위해 관심사를 분리하여 애플리케이션의 전체 동작 방식을 구성하기 위해 구현 객체를 생성하고 연결하는 책임을 가진 AppConfig를 개발했다. 이제 클라이언트 객체들은 자신의 역할을 수행하는 데 집중할 수 있게 되었다.

그러나 AppConfig에서 역할에 따른 구현을 확실하게 파악하기 힘들어, 역할과 구현을 명확하게 분리하여 잘 드러날 수 있도록 리팩터링을 거쳤다.

그래서 문제 발생의 시작인 새로운 할인 정책 적용을 객체 지향 설계 원칙을 지키며 변경할 수 있게 되었다.

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

지금까지 예제를 만들어 보면서 총 3가지, SRP • OCP • DIP를 적용했다.

SRP 단일 책임 원칙

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

처음에는 클라이언트 객체가 직접 구현 객체를 생성하고 연결, 실행하는 역할까지 다양한 책임을 가지고 있었다. 그래서 SRP를 지키기 위해, 구현 객체를 생성하고 연결하는 책임을 가진 AppConfig를 추가하였다. 이로써 클라이언트 객체는 실행하는 책임만 담당할 수 있게 되어 SRP를 준수할 수 있었다.

DIP 의존관계 역전 원칙

프로그래머는 ‘추상화’에 의존해야 하고, ‘구체화’에 의존하면 안 된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나이다.

새로운 할인 정책을 개발하여 적용하고자 할 때 클라이언트 코드도 함께 변경해야 했다. 기존 클라이언트 코드(OrderServiceImpl)가 DiscountPolicy 추상화 인터페이스 뿐만 아니라 FixDiscountPolicy 구체화 구현 클래스에도 의존했기 때문이다. 그래서 클라이언트 코드가 DiscountPolicy 추상화 인터페이스에만 의존하도록 코드를 변경했다. 구현체는 AppConfig가 구현 객체를 대신 생성하여 클라이언트 코드에 의존관계를 주입해 주었다. 이로써 DIP를 준수할 수 있게 되었다.

OCP 개방-폐쇄 원칙

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

다형성을 사용하고 클라이언트가 DIP를 지키며, 애플리케이션을 사용 영역과 구성 영역(AppConfig)으로 나누었다. 그래서 할인 정책을 FixDiscountPolicy에서 RateDiscountPolicy로 변경할 때, AppConfig가 의존관계를 변경하여 클라이언트에 코드를 주입하면 되기 때문에 클라이언트 코드는 변경을 하지 않아도 된다. 소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다. 이로써 OCP도 준수할 수 있게 되었다.


그동안 스프링을 사용하지 않고 순수 자바 코드만으로 개발을 했다. 다음 시간에는 지금까지 좋은 객체 지향 설계 5가지 원칙이 어떻게 반영되었는지 살펴보고, DI와 IoC 그리고 컨테이너에 대해 이론적인 공부를 해본다.

profile
좋은 개발자가 되자.

0개의 댓글