FrameWork/Spring&Spring-boot

Spring 기본3 - 객체 지향 원리 적용, OCP,DIP 위반의 문제

Surge100 2023. 11. 9. 11:21

객체 지향 원리 적용3

새로운 할인 정책 개발

*새로운 할인 정책을 확장해 보자*

https://agilemanifesto.org/iso/ko/manifesto.html

 

애자일 소프트웨어 개발 선언

애자일 소프트웨어 개발 선언 우리는 소프트웨어를 개발하고, 또 다른 사람의 개발을 도와주면서 소프트웨어 개발의 더 나은 방법들을 찾아가고 있다. 이 작업을 통해 우리는 다음을 가치 있게

agilemanifesto.org

 

RateDiscountPolicy추가

 

새로운 할인 정책 적용과 문제점

*방금 추가한 할인 정책을 적용해 보자

 

할인 정책을 어플리케이션에 적용해보자

할인 정책을 변경하려면 클라이언트인 OrderServiceImpl 코드를 수정해야 한다.

 

public class OrderServiceImpl implements OrderService{

//    private  final MemberRepository memberRepository = new MemoryMemberRepository();
    private  final DiscountPolicy discountPolicy = new FixDiscountPolicy();

	...
}

 

*문제점 발견*

  • 역활과 구현을 충실하게 분리했다 → OK
  • 다형성도 활용하고, 인터페이스와 구현 객체를 분리 했다. →  OK
  • OCP, DIP 같은 객체지향 설계 원칙을 충실히 준수 했다.
    • → 그렇게 보이지만 사실은 아니다.
  • DIP : 주문서비스 클라이언트 (OrderServiceImpl)는 DiscountPolicy 인터페이스에 의준하면서 DIP를 지킨거 같아 보인다 과연 그럴까? 
    • DiscountPolicy discountPolicy = new FixDiscountPolicy(); 와 같은 인스턴스 생성을 보면 추상(인터페이스) 뿐만 아니라 구체(구현)클래스에도 의존 하고 있다는것을 확인할 수 있다.
    • 추상(인터페이스) 의존 : DiscountPolicy
    • 구체(구현)클래스 :  FixDiscountPolicy, RateDiscountPolicy
  • OCP : 변경하지 않고 확장할 수 있어야 한다.
    • → 지금 코드는 기능을 확장해서 변경하면, 클라이언트 코드에 영향을 준다. 따라서 OCP를 위반 한것이다.

왜 클라이언트 코드를 변경해야 할까?

클래스 다이어그램으로 의존관계를 분석해보자

 

*기대 했던 의존관계*

지금까지 단순히 DiscountPolicy인터페이스만 의존한다고 생각했다.

 

*실제 의존관계*

//private  final DiscountPolicy discountPolicy = new FixDiscountPolicy();
  private  final DiscountPolicy discountPolicy = new RateDiscountPolicy();

잘보면 클라이언트 OrderServiceImpl이 DiscountPolicy 인터페이스 뿐만 아니라 FixDiscountPolicy인 구체 클래스도 함께 의존하고 있다. 실제 코드를 보면 의존하고 있음을 부인할 수없다.(DIP 위반)

 

*정책 변경*

중요! : 그래서 FixDiscountPolicy를 RateDiscountPolicy 로 변경하는 순간 OrderServieceImpl의 소스코드도 함께 변경해야 한다. (OCP위반)

 

어떻게 문제를 해결할 수 있을까?

  • 클라이언트 코드인 OrderServiceImpl은 DiscountPolicy의 인터페이스 뿐만 아니라 구체 클래스도 함께 의존한다.
  • 그래서 구체 클래스를 변경할 때 클라이언트 코드도 함께 변경한다.
  • DIP 위반  → 추상에만 의존하도록 변경(인터페이스에만 의존)
  • DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경하면 된다.

 

*인터페이스에만 의존하도록 설계를 변경하자*

*인터페이스에만 의존하도록 코드 변경*

public class OrderServiceImpl implements OrderService{
	private  DiscountPolicy discountPolicy;
  }
  • 인터페이스에만 의존하도록 코드를 변경했다.
  • 그런데 구현체가 없는데 어떻게 코드를 실행할 수 있을까?
  • 실제로 실행을 해보면 NPE(null pointer exeception)가 발생한다.

 

 

*해결방안*

  • 이 문제를 해결하려면 누군가가 클라이언트인 OrderServiceImpl 에 DiscountPolicy의 구현 객체를 대신 생성하고 주입해야한다.

 

 

 

 

[출처 - 스프링 핵심 원리 - 기본편]

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢

www.inflearn.com