비즈니스 요구사항과 설계
- 회원
- 회원 가입, 회원 조회 기능
- 일반 / VIP 등급
- 회원 데이터: 자체 DB 구축 or 외부 시스템과 연동(미확정)
- 주문과 할인 정책
- 회원은 상품 주문 가능
- 회원 등급에 따라 할인 정책을 적용
- 할인 정책: 변경 가능성 높음 (모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용 or 정률 적용 or 미적용)
- 회원 데이터, 할인 정책: 지금 결정하기 어려움. 그렇다고 이런 정책이 결정될 때까지 개발을 무기한 기다릴 수도 없음.
➡️ 인터페이스를 만들고 구현체를 언제든지 갈아끼울 수 있도록 설계 - 참고: 우선 스프링 없는 순수한 자바로만 개발을 진행
회원 도메인 설계
회원 도메인 요구사항
- 회원 가입, 회원 조회 기능
- 일반 / VIP 등급
- 회원 데이터: 자체 DB 구축 or 외부 시스템과 연동(미확정)
회원 도메인 협력 관계

회원 클래스 다이어그램(정적)

회원 객체 다이어그램(동적)

회원 도메인 개발 & 실행 & 테스트
- 회원 엔티티
- 회원 등급: member>Grade.java (Eunm)
- 회원 엔티티: member>Member.java
- 회원 저장소
- 회원 저장소 인터페이스: member>MemberRepository.java
- 메모리 회원 저장소 구현체: member>MemoryMemberRepository.java
(데이터베이스가 확정이 안되어, 가장 단순한 메모리 회원 저장소 구현)
- 회원 서비스
- 회원 서비스 인터페이스: member>MemberService.java
- 회원 서비스 구현체: member>MemberServiceImpl.java
- 회원 도메인: MemberApp.java
- 회원 가입 테스트: test>MemberServiceTest.java
⚠️ 회원 도메인 설계 문제점
- 의존 관계가 인터페이스뿐만 아니라 구현까지 모두 의존 ➡︎ OCP, DIP 주순 X
주문과 할인 도메인 설계
주문과 할인 정책
- 회원은 상품 주문 가능
- 회원 등급에 따라 할인 정책을 적용
- 할인 정책: 변경 가능성 높음 (모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용 or 정률 적용 or 미적용)
주문 도메인, 협력, 역할, 책임

- 주문 생성: 클라이언트 - 주문 서비스에 주문 생성을 요청
- 회원 조회: 주문 서비스 - 회원 저장소에서 회원 조회(할인을 위해 회원 등급 확인)
- 할인 적용: 주문 서비스 - 회원 등급에 따른 할인 여부를 할인 정책에 위임
- 주문 결과 반환: 주문 서비스 - 할인 결과를 포함한 주문 결과 반환
주문 도메인 전체

- 역할과 구현을 분리해서 자유롭게 구현 객체를 조립할 수 있게 설계
➡️ 회원 저장소, 할인 정책 유연하게 변경 가능
주문 도메인 클래스 다이어그램

주문 도메인 객체 다이어그램1

- 회원을 메모리에서 조회하고, 정액 할인 정책을 지원해도 주문 서비스를 변경하지 않아도 됨. 협력 관계 그대로 재사용 가능
주문 도메인 객체 다이어그램2

- 회원을 실제 DB에서 조회하고, 정률 할인 정책을 지원해도 주문 서비스를 변경하지 않아도 됨. 협력 관계 그대로 재사용 가능
주문과 할인 도메인 개발 & 실행 & 테스트
- 할인
- 할인 정책 인터페이스: discount>DiscountPolicy.java
- 정액 할인 정책 구현체: discount>FixDiscountPolicy.java
- 정률 할인 정책 구현체: discount>RateDiscountPolicy.java
- 주문 서비스
- 주문 서비스 인터페이스: order>OrderService.java
- 주문 서비스 구현체: order>OrderServiceImpl.java
- 주문 엔티티: order>Order.java
- 주문 도메인: OrderApp.java
- 테스트
- 주문/할인 테스트: test>OrderServiceTest.java
- 정률 할인 테스트: test>RateDiscountPolicyTest.java
할인 정책 변경
- 할인 정책을 변경하려면 클라이언트인 OrderServiceImpl 코드를 고쳐야 함
public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}

⚠️ 문제점
- DIP 위반: 주문 서비스 클라이언트(OrderServiceImpl)는 추상(인터페이스) 뿐만 아니라 구체(구현) 클래스에도 의존
- 추상(인터페이스) 의존: DiscountPolicy
- 구체(구현) 클래스 의존: FixDiscountPolicy, RateDiscountPolicy
- OCP 위반: 기능 확장해서 변경하려면 클라이언트 코드에 영향을 줌
- FixDiscountPolicy 를 RateDiscountPolicy 로 변경하는 순간 OrderServiceImpl 의 소스 코드도 함께 변경
‼️ 해결
- DIP 위반 - 추상(인터페이스)에만 의존하도록 의존 관계 변경
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
- 구현체가 없어서 코드 실행 불가
➡️ 누군가가 클라이언트인 OrderServiceImpl 에 DiscountPolicy 의 구현 객체를 대신 생성하고 주입해주어야 함
'Spring' 카테고리의 다른 글
[Spring] 좋은 객체 지향 설계 / IoC(Inversion of Control) / DI(Dependency Injection) (2) | 2024.09.21 |
---|---|
[Spring] 자바 프로젝트 생성 - DIP / OCP 규칙 준수하도록 변경하기, 리팩터링 (0) | 2024.09.21 |
[Spring] 객체 지향 설계, 다형성, SOLID (2) | 2024.09.20 |
[Spring] AOP(Aspect Oriented Programming) (0) | 2024.09.12 |
[Spring] H2, JDBC, JPA / 통합 테스트 (1) | 2024.09.11 |