[About Spring] 쇼핑몰 실습

고지훈·2022년 11월 22일
0

About Spring

목록 보기
4/4

Record: 2022.11.21 /

비지니스 요구사항과 설계

쇼핑몰 예제 실습에서 필요한 요구사항은 다음과 같다.

  1. 회원
    • 사용자는 회원가입을 할 수 있고, 회원정보를 조회할 수 있다.
    • 회원등급은 일반등급과 VIP등급이 있다.
    • 회원 데이터 베이스는 메모리 DB를 사용할 수도 있고, RDBMS를 사용할 수도 있다.
  2. 주문과 할인
    • 회원은 상품을 주문할 수 있다.
    • 회원의 등급에 따라 할인되는 비율이 다르다.
    • 회원의 할인정책은 회사 내부적인 상황에 따라 종료될 수도 있고, 할인 폭이 더욱 커질 수도 있다.

위 요구사항을 보면, DB나 할인정책은 변경될 수 있다. 다형성을 생각하여 인터페이스로 개발을 진행해보자!


주문 도메인

  • 주문생성: 클라이언트는 주문 서비스에 주문 생성을 요청
  • 회원조회: 할인을 위해서는 회원 등급이 필요하다. 주문 서비스는 저장소에서 회원을 조회한다.
  • 할인적용: 주문 서비스는 회원 등급에 따른 할인 여부를 할인 정책에 위임한다.
  • 주문결과 반환: 주문 서비스는 할인 결과를 포함한 주문 결과를 반환한다.

할인정책 변경 적용

할인정책을 변경하기 위해서는 현재 클라이언트의 코드를 변경해주어야 한다. 그 예제는 아래와 같다.

// private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); → 변경전
private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); → 변경후
  • 위 코드에서 확인할 수 있는 사항은 다음과 같다.
    1. 역할과 구현을 충실하게 분리하였다.
    2. 다형성도 활용하고 인터페이스와 구현 객체를 분리하였다.
    3. OCP, DIP와 같은 객체지향 설계 원칙을 충실히 준수했다. → X
      • 현재 위 코드는 추상 인터페이스 뿐만 아니라 구현 클래스에도 의존하고 있다는 것을 알 수 있다.
      • 추상 인터페이스 의존: DiscountPolicy
      • 구현 클래스: FixDiscountPolicy, RateDiscountPolicy
    4. 즉, 현재의 코드는 기능을 확장하여 변경하면 클라이언트 코드에 영향을 준다 따라서 OCP를 위반한다.

자! 이제 OCP를 위반했기 때문에 해결방안을 생각해보자. 해결방안은 다음과 같다.

  • 클라이언트 코드인 OrderServiceImplDiscountPolicy의 인터페이스 뿐만 아니라 구체 클래스도 함께 의존한다. 그래서 구체 클래스를 변경할 때 클라이언트 코드도 함께 변경해야한다.
  • DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경시킨다.

코드로 표현하자면 다음과 같다.

private final DiscountPolicy discountPolicy;

위 방식대로 메서드를 호출할 경우 Null포인트 Exception이 발생할 것이다. 왜? → 그 이유는 객체를 할당해주지 않았기 때문이다.

Config파일을 하나 생성하여 구현 객체의 생성을 하나의 클래스로 관리하자

public class AppConfig {

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

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

위 코드를 통해 DIP를 만족할 수 있다.

profile
"계획에 따르기보다 변화에 대응하기를"

0개의 댓글