https://start.spring.io 사이트에서 스프링 프로젝트 생성
회원
주문과 할인 정책
미확정인 부분이 결정될때까지 기다릴 수 없음 → 객체 지향 설계 : 역할과 구현을 구분하여 해결하도록 한다
회원
저장소는 아직 미정임
→ 메모리 회원 저장소를 임시로 사용하기로 결정
회원 클래스 다이어그램
멤버서비스 인터페이스와 멤버서비스 구현(Implement) : 회원 서비스멤버 리포지토리 : 회원 저장소 → 구현체를 메모리 멤버 저장소, DB 회원 저장소로 구분 (외부 시스템 연동 회원 저장소도 추가 가능)
해당 그림으로 실제 개발을 한다고 보면됨
hello.core 폴더안에 member package
생성
package hello.core.member;
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
// 인터페이스에 구현체 대입
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
멤버저장소 인터페이스에 메모리 멤버 저장소 구현체 대입 join함수에 save, findMember에 findById 연결해 줌으로서 구현 완료테스트
package hello.core;
import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
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()); // 회원 조회해서 찾은 멤버
}
}
main 어플리케이션 대신 test 어플리케이션에서 테스트 가능 : Assertions
를 활용
package hello.core.member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
public class MemberSerivceTest {
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);
}
}
테스트 돌렸을 때 실패하면 빠르게 캐치 가능. 사용하면 좋다
회원 도메인 설계의 문제점
private final MemberRepository memberRepository = new MemoryMemberRepository();
위의 구문에서 memberRepository가 인터페이스뿐만아닌 구현체에도 의존주문과 할인 정책
위와같이 역할과 구현을 분리할 수 있음
DB멤버 저장소로 변경하거나 정률 할인 정책으로 변경하는 것이 쉬움
구현체만 갈아끼우면 됨
현재는 메모리 멤버 저장소, 정액 할인 정책을 사용할 것
Discount
패키지
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
public class FixDiscountPolicy implements DiscountPolicy{
private int discountFixAmount = 1000;
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP){
return discountFixAmount;
}else{
return 0;
}
}
}
order
패키지
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member memeber = memberRepository.findById(memberId); // 회원정보 조회
// 할인정책에 멤버 넘김 : 할인 정책 클래스에서 회원 등급에 따른 할인 금액을 계산해서 리턴해줌
int discountPrice = discountPolicy.discount(memeber, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
test
package hello.core.order;
import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
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);
}
}
인프런 스프링 핵심 원리 기본편 - 김영한 강의를 듣고 정리한 내용입니다