- 해당 게시물은 인프런 "스프링 핵심 원리 - 기본편" 강의를 참고하여 작성한 글 입니다.
기획자로부터 아래의 요구사항을 듣게 된다.
1) 회원
2) 주문과 할인 정책
1) 회원
2) 도메인 협력 관계
기획자도 보는 그림이다. 도메인 협력 관계를 기반으로 클래스 다이어그램을 그린다.
3) 클래스 다이어그램
실제 구현 레벨로 내려오면 클래스, 인터페이스 명세를 작성한 클래스 다이어그램이 필요하다.
클래스 간의 의존 관계, 연관 관계, 제약 조건 등을 기반으로 개발한다.
4) 객체 다이어그램 : 런타임에서 객체가 생성됬을 때의 시나리오를 다이어그램으로 표현
1) 회원 엔티티
2) 회원 저장소
메모리 회원 저장소는 동시성 이슈 때문에 실무에서는 ConcurrentHashMap을 써야 하지만, 간단한 하게 HashMap을 쓴다. 아래 링크를 참고하자
https://tecoble.techcourse.co.kr/post/2021-11-26-hashmap-hashtable-concurrenthashmap/
private static Map<Long, Member> store = new HashMap<>(); // 메모리 저장소
3) 회원 서비스
public class MemberServiceImpl implements MemberService{
// 구현 객체를 MemoryMemberRepository 로 선택해주자
private final MemberRepository memberRepository = new MemoryMemberRepository();
1) JUnit Test Framework를 이용한다.
단축키로 간편하게 만들 수 있다. 아래 링크를 참고하자
https://theamabile.tistory.com/21
2) 회원 서비스에서 저장 및 조회 JUnit 테스트 코드
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);
}
}
의존 관계가 인터페이스 뿐만 아니라 구현까지 모두 의존하는 문제가 있다.
public class MemberServiceImpl implements MemberService{
// 구현 객체를 MemoryMemberRepository 로 선택해주자
private final MemberRepository memberRepository = new MemoryMemberRepository();
MemberServiceImpl 구현체가 MemberRepository 인터페이스 뿐만 아니라, MemoryMemberRepository 구현체 까지 모두 의존하고 있다.
-> DIP위반
1) 주문과 할인 정책 요구사항
2) 주문 도메인 협력, 역할, 책임 : 기획자와 개발자가 구상하는 설계도
3) 주문 도메인 전체 : 역할과 구현의 분리
구현 객체가 점선 화살표로 인터페이스를 바라보고 있다.
-> 회원 저장소는 물론이고 할인 정책도 유연하게 변경할 수 있다.
4) 클래스 다이어그램 : 정적 정보. 클래스, 인터페이스의 명세
5) 객체 다이어그램 : 동적 정보. 런타임에서 특정 순간에 객체 간의 관계 및 상황을 표현
구현내용 : 주문 생성 요청이 오면, 회원 정보를 조회하고, 할인 정책을 조회 한 다음 주문 객체를 생성해서 반환한다.
1) 할인 정책 인터페이스 : interface DiscountPolicy
2) 고정 할인 정책 구현체 : class FixDiscountPolicy
3) 주문 엔터티 : class Order
엔터티 클래스에 toString 메소드를 재정의하면 객체의 이름이나 주소값이 아닌 객체의 고유 정보를 출력할 수 있다.
https://inpa.tistory.com/entry/JAVA-%E2%98%95-toString-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%9E%AC%EC%A0%95%EC%9D%98-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
4) 주문 서비스 인터페이스 : interface OrderService
5) 주문 서비스 구현체 : class OrderServiceImpl
JUnit 테스트 코드
public class OrderServiceTest {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
@Test
void createOrder(){
Long memberId = 1L; // null 이 들어갈 수도 없어서 wrapper type 썼음
Member member = new Member(memberId, "itemA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
}
}
다형성만을 이용해서 중간에 DIP위반을 한 것을 제외하고는 성공적이었다.
다음 시간에는 갑자기 악덕 기획자가 나타나서 요구사항을 바꿀 것이다.
할인 정책이 바뀌어도 큰 문제가 없을지 '객체 지향 원리'를 적용해서 해결하자.