JAN's History

2주차_스프링 본문

스프링

2주차_스프링

JANNNNNN 2023. 4. 9. 13:00

목차

1. 프로젝트 생성

2. 비즈니스 요구사항과 설계

3. 회원 도메인 설계

4. 회원 도메인 개발

5. 회원 도메인 실행과 테스트

6. 주문과 할인 도메인 설계

7. 주문과 할인 도메인 개발

8. 주문과 할인 도메인 실행과 테스트

 

 

회원 도메인 설계

- 회원을 가입하고 조회할 수 있다.

- 회원은 일반과 VIP 두 가지 등급이 있다.

- 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다.(미확정)

회원 도메인 협력관계

1. 메모리 회원 저장소가 간단한 구조이기 떄문에 메모리 회원 저장소로 일단 개발을 진행

2. 추후에 데이터베이스가 선택이 되면 역할과 구현을 나눠 갈아끼우는 형태를 계획

ex) 기름자동차 -> 전기자동차처럼!

회원 클래스 다이어그램

실제 구현 레벨로 내려오면 위 그림과 같은 다이어그램이 생성된다.

1. 멤버서비스(회원가입,회원조회)의 역할을 MemberService인터페이스로 만들고

그에 대한 구현을 MemberServiceImpl로 개발한다.

2. 회원 저장소역할을 MemberRepository가 하고

그에 대한 구현클래스로 MemoryMemberRepository과 DbMemberRepository가 된다.

회원 객체 다이어그램

회원서비스 = MemberServiceImpl

실제 서버에서 객체간의 메모리 참조를 나타낸 다이어그램

 


회원 서비스

멤버 (ID, NAME, GRADE) 생성

Member의 값이 private이기 때문에 간접적으로 읽을 수 있는 getter와 setter도 아래에 생성했다.

Member은(id, name, grade)로 구성되어 있으며 초기화도 진행해주었다.

MemberRepository 인터페이스

회원저장소 인터페이스에는 회원정보를 저장하고(save) 찾는 추상 메서드(findById)를 생성했다.

save(Member member) -> class member에 선언된 객체 memeber를 저장한다.

findByID(Long memberId) -> Long타입의 memberId를 받으면 memberId를 반환한다.

MemberRepository 메모리버전 구현

Map<Long, Member> store = new HashMap<> - Map이 HashMap을 구현한 인터페이스이기 때문에

List<Long, Member> stroe = new ArrayList<>처럼 Map와 List를 직접 생성할 순 없음!

Map은 <key, Value>값을 저장하고 특정 데이터의 저장위치를 해시함수를 통해 바로 알 수 있기 때문에 데이터의 추가, 삭제, 특히 검색이 빠르다는 장점이 있어 사용한다.

+hashMap 순서X, 중복O(keyX, valueO)

save - put으로 mamber의 ID와 member요소를 저장한다.

findById - memberId의 값을 읽어 반환한다.

MemberService 인터페이스

회원서비스는 회원가입과 회원조회 기능 2가지만 제공.

MemberService 에 대한 구현

회원가입을 하고 아이디를 찾기 위해선 MemoryMemberRepository에서 put된 멤버들이 필요하다.

그렇기 때문에 MemberRepository 인터페이스에서 구현된 MemoryMemberRepository()를 memberRepository로 객체를 생성해줘 사용하기로 한다.

그래서 다형성으로 memberRepository의 메서드인 save를 사용해 join하고 findById를 사용해 findMember 할 수 있다.


회원도메인 실행과 테스트

테스트 코드

=> memberld 1L이 같으므로 성공

*Test 코드는 매우 중요!*

테스트코드

그러나 junit으로 테스트 하는 것이 더 효율적이다.

위에서 코드는 눈으로 직접 같은지 확인해야하지만 junit을 사용하면 런타임이 제대로 돌아가면 성공이라는 뜻이기 때문!

회원 도메인 문제점

OCP 원칙을 잘 준수하는지?

DIP를 잘 지키고 있는지?

=> 의존관계가 인터페이스, 구현까지 모두 의존하는 문제점 발생.


주문과 할인 도메인 설계

주문과 할인 정책

- 회원은 상품을 주문할 수 있다.

- 회원 등급에 따라 할인 정책을 적용할 수 있다.

- 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라.(나중에 변경될 수 있다.)

- 할인 정책은 변경 가능성이 높다. 최악의 경우 할인을 적용하지 않을 수 있다.(미확정)

=> 역할과 구현을 분리하여 개발해보자!

주문 도메인 협력, 역할, 책임만 표시.

1. 주문 생성: 클라이언트는 주문 서비스에 주문 생성을 요청한다.

2. 회원 조회 : 할인을 위해선 회원등급이 필요하다. 그래서 주문 서비스는 회원 저장소에서 회원을 조회한다.

3. 할인 적용 : 주문 서비스는 회원등급에 따른 할인 여부를 할인 정책에 위임한다.

4. 주문 결과 반환 : 주문 서비스는 할인 결과를 포함한 주문 결과를 반환한다.

 

주문 도메인 전체(역할+구현)

역할과 구현을 분리하여 자유롭게 구현 객체를 조립할 수 있게 설계했다. 

덕분에 회원 저장소는 물론이고, 할인 정책도 유연하게 변경할 수 있다.

주문 도메인 클래스 다이어그램

(~~Impl -> 구현)

1. 오더서비스에 대한 인터페이스: OrderService

그에 대한 구현 객체: OrderServicelmpl

2. 회원저장소에 대한 인터페이스: MemberRepositoty

그에 대한 구현 객체: MemoryMemberRepository, DbMemberRepository.

3. 할인 정책에 대한 인터페이스: DiscountPolicy

그에 대한 구현 객체: FixDiscountPolicy, RateDiscountPolicy.

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

회원을 메모리에서 조회하고, 정액 할인 정책(고정금액)을 지원해도 주문 서비스를 변경하지 않아도 된다.

역할들의 협력 관계를 그대로 재사용할 수 있다.

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

회원을 메모리가 아닌 실제 DB에서 조회하고, 정률 할인 정책(주문 금액에 따라 %할인)을 지원해도 주문 서비스를 변경하지 않아도 된다. 

=> 협력 관계를 그대로 재사용할 수 있다.

주문과 할인 도메인 개발

주문 (memberId, itemName, itemPrice, discountPrice) 생성
주문 인터페이스
할인 인터페이스

member 에 따라 discount 값을 반환할 추상메서드를 생성한다.

FixDiscountPolicy 개발

discount에서 member의 Grade가 VIP면 discountFixAmount를 1000으로 반환하고 아니면 0으로 반환한다.

주문 서비스 구현 객체

주문생성 요청이 오면 memberRepository를 통해 회원 정보를 조회하고

discountPolicy를 통해 멤버 이름과 상품 가격을 넘긴 후 할인 가격을 알 수 있도록 했다.

+discountPolicy를 따로 분리함으로써 만약 할인 금액이 변경될 경우 한 파일만 수정하면 되기 때문에 좋은 설계인 것!

주문과 할인 도메인 실행과 테스트

테스트 코드

=> VIP인 경우 1000원 할인해주기로 했으므로 memberA(VIP)의 할인 금액이 1000원 인 것이 검증되었으므로 성공!!

'스프링' 카테고리의 다른 글

7주차_스프링  (0) 2023.05.29
6주차_스프링  (0) 2023.05.22
5주차_스프링  (0) 2023.05.15
4주차_스프링  (1) 2023.05.08
3주차_스프링  (0) 2023.05.02