[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() 중복 제거 
    • 역할과 구현 클래스가 한눈에 들어와 애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악 가능

    + Recent posts