hoon's bLog

Spring gradle project 스프링 핵심 원리 기본편 | AppConfig 리팩토링 OCP 위반 해결 및 중복 제거 본문

IT/Spring

Spring gradle project 스프링 핵심 원리 기본편 | AppConfig 리팩토링 OCP 위반 해결 및 중복 제거

개발한기발자 2024. 4. 1. 16:47
반응형


본 포스팅은 인프런에 있는 인터넷 강좌인,

김영한 강사님의 스프링 핵심 원리 기본편을 공부하며,

개인적으로 공부하고, 정리하는 용도로 포스팅을 해보겠다.

 

[이전 포스팅 목록]

Spring gradle project 환경설정 및 회원 가입 서비스 예제 만들기
Spring gradle project 주문/할인 도메인 설계

Spring gradle project 객체 지향 원리 적용

AppConfig 리팩토링

저번 포스팅에 말했던 AppConfig를 코드를 통해 알아보도록 하자.

package hello.core;

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

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }
    
    public OrderService orderService() {
        return new OrderServiceImpl(
                new MemoryMemberRepository(),
                new FixDiscountPolicy());
    }
}
  • 위 코드는 할인 정책을 FixDiscountPolicy에서 RateDiscountPolicy로 변경하고 싶을 때, AppConfig에서 해당 부분만 변경하려고 만든 목적이었다.
  • 하지만 MemoryMemberRepository의 인스턴스를 memberService()와 orderService()에서 각각 생성함으로써 중복되고 있다. 이는 리소스의 낭비와 함께 데이터 일관성을 유지하기 어렵게 만든다.
  • 현재 AppConfig는 구현 클래스를 직접 생성하고, 레포지토리의 구현체를 변경하고 싶을 때 AppConfig 내부의 코드를 변경해야 한다.
  • 열린-닫힌 원칙(Open/Closed Principle)을 위반하며, 애플리케이션의 확장성과 유지 보수성을 저하시킨다.
  • 이를 개선하기 위해 리팩토링 하면 아래 코드와 같다.

AppConfig 리팩토링

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;

public class AppConfig {
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
    
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(),discountPolicy());
    }
    
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    
    public DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
    }
}
  • 중복 제거 : memberRepository()라는 별도의 메소드를 통해 MemoryMemberRepository의 인스턴스를 생성하고 이를 memberService()와 orderService()에 주입한다.
  • 이로써 모든 서비스가 동일한 MemoryMemberRepository 인스턴스를 공유하게 되어 중복을 제거하고, 리소스 사용을 최적화한 것이다.
  • 역할과 구현의 분리 개선: 두 번째 코드는 DiscountPolicy와 MemberRepository 인터페이스에 대한 구현체를 생성하고 반환하는 별도의 메서드(discountPolicy(), memberRepository())를 제공한다.

리팩토링을 통해서 역할과 구현을 분리하는

스프링의 핵심 원칙을 더 잘 따르는 구조로 만들었다.

특정 구현체를 변경하고 싶을 때 해당 메서드의 내용만 변경하면 되므로,

애플리케이션의 나머지 부분에는 영향을 주지 않으면서 변경이 용이해진다.
이로써 코드는 더욱 깔끔해지고, 유지 보수와 확장성 측면에서 개선된다.

또한, 구성요소 간의 결합도를 낮추고, 의존성을 외부에서 주입하는 방식을 통해 시스템의 유연성을 증가시킨다.

 

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

  • 그림과 같이 AppConfig의 등장으로 애플리케이션이 크게 사용 영역과, 객체를 생성하고 구성(Configuration)하는 영역으로 분리되었다.
  • 그리고 기존에 FixDiscountPolicy를 RateDiscountPolicy로 정책을 바꾸려고 한다.
  • 이에 맞게 변경한 코드를 알아보자.

할인 정책 변경 구성 코드

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
 
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    public DiscountPolicy discountPolicy() {
        // return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}
  • AppConfig에서 할인 정책 역할을 담당하는 구현을 FixDiscountPolicy → RateDiscountPolicy 객체로 변경!!
  • 이제 할인 정책을 변경해도, 애플리케이션의 구성 역할을 담당하는 AppConfig만 변경하면 된다.
  • 구성 역할을 담당하는 AppConfig를 애플리케이션이라는 공연의 기획자로 생각하고, 공연 기획자는 공연 참여자인 구현 객체들을 모두 알아야 한다.
728x90
반응형