Backend/Spring

스프링 핵심 원리 이해 1, 2

HJ39 2024. 1. 4. 00:32

요구사항에 따른 코드 구현 및 설계도는 생략하였다.

 

□ 문제점 코드

public class OrderServiceImpl implements OrderService {
 //    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
     private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
 }

이런 코드의 경우 OrderServiceImpl 는 Interface인 OrderService 에 의존하고 있다. (설계된 의도)

FixDiscountPolicy(), RateDiscountPolicy()를 직접적으로 객체를 생성하므로 두 클래스에도 의존을 하게된다. → DIP를 지키지 못했다.

 

□ 원래 목적 

 

□ 잘못된 의도

 

□ 요구사항이 변경된 경우 클라이언트 코드를 직접 수정해야함

클라이언트 코드를 수정하여 OCP를 위반한다.

 

해결방법

  • Interface에 의존하게끔 변경한다.
public class OrderServiceImpl implements OrderService {
     //private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
     private DiscountPolicy discountPolicy;
}

 

 

  • 외부 클래스를(AppConfig) 생성하여 객체를 주입시켜 준다.
public class AppConfig {
     public MemberService memberService() {
         return new MemberServiceImpl(new MemoryMemberRepository());
     }

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

 

 

  • OrderServiceImpl에 생성자 생성
public class OrderServiceImpl implements OrderService {
     private final MemberRepository memberRepository;
     private final DiscountPolicy discountPolicy;
     public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
         this.memberRepository = memberRepository;
         this.discountPolicy = discountPolicy;
     }
}

 

위와 같은 방식으로 수정하면

 

□ 변경된 후 클래스 다이어그램

 

 

조금 더 코드를 깔끔하게 수정하면!!

 

□ 리팩토링한 AppConfig

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();
     }
}

메소드를 각자의 역할에 맞게 분리하였다.

 

결론

이렇듯 interface로 역할을 나눈 뒤 class가 역할을 수행하도록만 구현하면 요구사항이 변해도 손쉽게 갈아끼울 수 있다.

요구사항이 변해도 사용 영역의 코드는 변하면 안된다!! (중요!)

→ 사용 영역 코드가 변한다면 잘못 설계한 것! 🫢

'Backend > Spring' 카테고리의 다른 글

Component Scan  (0) 2024.01.09
Singleton Container  (0) 2024.01.09
Container와 Bean  (0) 2024.01.08
객체지향원칙 5가지  (0) 2024.01.04