Spring

[Spring] 자바 프로젝트 생성 - DIP / OCP 규칙 준수하도록 변경하기, 리팩터링

jelliclesu 2024. 9. 21. 12:23
 

[Spring] 자바 프로젝트 생성 - 인터페이스와 구현의 구분, DIP / OCP 규칙 위반 예시

비즈니스 요구사항과 설계회원회원 가입, 회원 조회 기능일반 / VIP 등급회원 데이터: 자체 DB 구축 or 외부 시스템과 연동(미확정)주문과 할인 정책회원은 상품 주문 가능회원 등급에 따라 할

jelliclesu.tistory.com


AppConfig 생성

AppConfig.java

  • 애플리케이션의 전체 동작 방식을 구성(config)하기 위해, 구현 객체를 생성하고, 연결하는 책임을 가지는 별도의 설정 클래스
  • 사용 영역, 객체를 생성하고 구성(Configuration)하는 영역으로 분리
  • 구현 객체 생성
    • MemberServiceImpl
    • MemberRepository
    • OrderServiceImpl
    • DiscountPolicy
  • 생성자를 통한 주입(연결) - 인스턴스의 참조(레퍼런스)
    • MemberServiceImpl ➡︎ MemoryMemberRepository
    • OrderServiceImpl ➡︎ MemoryMemberRepository, DiscountPolicy

 

생성자 주입

  • 생성자를 통해 어떤 구현 객체가 들어올지(주입될지)는 알 수 없음 - 오직 외부(AppConfig)에서 결정
  • MemeberServiceImpl.java
    • MemoryMemberRepository 를 의존하지 않고, MemberRepository 인터페이스만 의존 ➡️ DIP 준수
  • OrderServiceImpl.java
    • FixDiscountPolicy 를 의존하지 않고, DiscountPolicy 인터페이스만 의존 ➡️ DIP 준수
    • MemoryMemberRepositoryDiscountPolicy 객체의 의존관계가 주입

 

할인 정책 수정

  • 구성 역할을 담당하는 AppConfig만 변경하면 됨 - OrderServiceImpl 를 포함해서 사용 영역의 어떤 코드도 변경 X

 

 

클래스 다이어그램

  • 객체의 생성과 연결은 AppConfig 가 담당
  • DIP 준수: MemberServiceImpMemberRepository 인 추상에만 의존
  • 관심사의 분리: 객체를 생성하고 연결하는 역할과 실행하는 역할이 명확히 분리

 

회원 객체 인스턴스 다이어그램

 

  • appConfig 객체는 memoryMemberRepository 객체를 생성, 그 참조값을 memberServiceImpl 을 생성하면서 생성자로 전달
  • 클라이언트인 memberServiceImpl 입장에서 보면 의존관계를 마치 외부에서 주입 - DI(Dependency Injection: 의존성 주입)

 

AppConfig 실행

  • MemberApp.java / OrderApp.java 에 AppConfig 적용
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
OrderService orderService = appConfig.orderService();

 

AppConfig 리팩터링

 

리팩터링 전

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }

    public OrderSerive orderSerive() {
        return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy()
        );
    }

}
  • 중복이 있으며, 역할에 따른 구현이 잘 보이지 않음

 

리팩터링 후

public class AppConfig {

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

    private MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    public OrderSerive orderSerive() {
        return new OrderServiceImpl(memberRepository(), discountPolicy()
        );
    }

    private DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
    }

}
  • new MemoryMemberRepository() 중복 제거 
  • 역할과 구현 클래스가 한눈에 들어와 애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악 가능