월루를 꿈꾸는 대학생
[핵심 원리-기본]비즈니스 요구사항과 설계 본문
비즈니스 요구사항과 설계
회원
- 회원을 가입하고 조회할 수 있다.
- 회원은 일반과 VIP 두 가지 등급이 있다.
- 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)
주문과 할인 정책
- 회원은 상품을 주문할 수 있다.
- 회원 등급에 따라 할인 정책을 적용할 수 있다.
- 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있
다.) - 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)
회원데이터 및 할인 정책은 아직 결정되지 않았기 때문에 무기한 대기일 수도 있다 그래서 인터페이스를 만들고 구현체를 언제든지 갈아끼울 수 있도록 설계해야한다
회원 도메인 설계
회원 도메인 요구사항
- 회원을 가입하고 조회할 수 있다.
- 회원은 일반과 VIP 두 가지 등급이 있다.
- 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)
회원 도메인 협력 관계
- 클라이언트가 회원서비스를 조회 후 저장소를 호출
- 저장소가 아직 안 정해졌으니까 인터페이스로
- 기획자도 볼 수 있음
- 클라이언트랑 서비스 저장소는 다 역할
- 저장소 구현체를 3가지 정도 해두고 요구사항에 따라 끼우면 됨 !
![[Pasted image 20230710010520.png]]
회원 클래스 다이어그램
- 멤버 서비스 역할을 인터페이스로 만듦
- 저장소 역할 또한 인터페이스 만듦
- 구현체는 2개
- 개발자가 만듦
![[Pasted image 20230710010533.png]]
회원 객체 다이어그램
- 클라이언트는 회원서비스 impl바라보고 회원서비스impl은 메모리 저장소
- 회원서비스 = memverserviceImpl
- 클라이언트가 실제 사용하는 인스턴스끼리의 참조
![[Pasted image 20230710010543.png]]
회원 클래스 다이어그램을 보고 만들면 된다
코드는 pdf참고
![[Pasted image 20230714011717.png]]
회원 엔티티
Member라는 기본 아이디, 이름, 등급을 가지는 클래스를 생성
회원 저장소
- MemberRepositry : 인터페이스임 해당 리포지토리에서는 회원을 저장 , 조회 기능을 가짐
- MemoryMemberRepository : 메모리에 데이터를 저장하는 구현체 , 데이터베이스가 정해지지 않아서 임시로 갈아끼울 구현체를 생성함
회원 서비스
- MemberService : 멤버를 추가 , 멤버를 찾는 기능을 한다
- MemberServiceImpl : 구현체임
회원 도메인 실행과 테스트
![[Pasted image 20230714012214.png]]
해당 흐름을 만든다
만들어 둔 거를 확인
public class MemberApp {
public static void main(String[] args) {
MemberService memberService = new MemberServiceImpl();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = : "+member.getName());
System.out.println("find member = : "+findMember.getName());
}
}
위와 같이 확인해도 되지만 junit
이라는 걸 사용할 예정
테스트할 때 쓰는 패키지
import org.assertj.core.api.Assertions;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
public class MemberServiceTest {
MemberService memberService = new MemberServiceImpl();
@Test
void join(){
//given
Member member = new Member(1L,"memberA",Grade.VIP);
//when
memberService.join(member);
Member findMember = memberService.findMember(1L);
//then
Assertions.assertThat(member).isEqualTo(findMember);
}
}
회원 도메인 설계의 문제점
- 다른 저장소로 변경할 때 OCP원칙 준수하는가?
- DIP잘 지키고 있는가
- *의존 관계가 인터페이스 뿐만 아니라 구현까지 모두 의존 하는 문제점 *
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
MemberServiceImpl보면
MemberRepository 추상화에도 의존을 하고 있고
MemorytMemberRepository 구현체에도 의존을 하고 있다
주문과 할인 도메인
요구사항 확인
- 회원 등급에 따라 할인 정책을 적용한다
- 모든 vip는 1000원 할인 하는 고정금액 할인 적용 -> 할인 정책은 변경 가능성 높음
![[Pasted image 20230714014020.png]]
- 주문 생성: 클라이언트는 주문 서비스에 주문 생성을 요청한다.
- 회원 조회: 할인을 위해서는 회원 등급이 필요하다. 그래서 주문 서비스는 회원 저장소에서 회원을 조회
한다. findById - 할인 적용: 주문 서비스는 회원 등급에 따른 할인 여부를 할인 정책에 위임한다.
- 주문 결과 반환: 주문 서비스는 할인 결과를 포함한 주문 결과를 반환한다.
주문 도메인 전체
![[Pasted image 20230714014205.png]]
역할을 먼저 만들고 구현을 만든다
역할과 구현을 나눠서 만들어서 자유롭게 조립이 가능하고 유연하게 교체가능
클래스 다이어 그램
![[Pasted image 20230714014341.png]]
주문 도메인 객체 다이어그램1
![[Pasted image 20230714014625.png]]
회원을 메모리에서 조회를 한 다음 정액 할인 정책을 지원해도 주문서비스 구현체는 변경 안 해도 됨
협력 관계를 그대로 재사용할 수 있다
주문 도메인 객체 다이어그램2
![[Pasted image 20230714014737.png]]
이렇게 해도 주문 서비스를 변경하지 않아도 된다!
협력 관계 그대로 사용 가능
- 주문결과 반환 이 오더서비스
public interface OrderService { Order createOrder(Long memerId , String itemName, int itemPrice); }
해당 구현체
public class OrderServiceImpl implements OrderService{
// 멤버리파지토리에서 회원 찾기 위해서
private final MemberRepository memberRepository = new MemoryMemberRepository();
// 고정율의 할인 정책
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Override
public Order createOrder(Long memerId, String itemName, int itemPrice) {
// 멤버를 찾고
Member member = memberRepository.findById(memerId);
// 설계가 잘 된 이유
// 오더서비스의 경우 할인에 대해서 잘 몰라! 할인에 대한 거는discountPolicy한테 오마카세함
// 단일체계원칙 잘 지킴 , 문제가 생기면 해당 부분만 고치면 됨
int dicountPrice = discountPolicy.discount(member,itemPrice);
// 할인된 주문 결과를 반환
return new Order(memerId,itemName,itemPrice, dicountPrice);
}
}
테스트 코드
public class OrderServiceTest {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
@Test
void createOrder(){
Long memberId = 1L;
Member member = new Member(memberId,"memberA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId,"itemA",10000);
Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
}
}
지금까지 한 거
![[Pasted image 20230714021104.png]]
여기서 정액할인과 메모리 회원 저장소를 사용
다음 챕터는 다형성을 활용해서 다른 구현체를 끼워보고 깔끔하게 되는지 다형성을 잘 활용했는지 확인할 것!
출처
'Programing > Spring Boot' 카테고리의 다른 글
[핵심원리-기본] 스프링 컨테이너와 스프링빈 (0) | 2023.07.18 |
---|---|
[핵심원리-기본] 객체지향 원리 적용 (0) | 2023.07.18 |
[스프링 핵심 원리 기본] 객체 지향 설계와 스프링 (0) | 2023.07.07 |
[SpringBoot] rest controller , post , json (0) | 2023.03.09 |
[SpringBoot] 게시판 만들기 feat) mybatis + jQuery (0) | 2023.03.08 |