본문 바로가기

Spring

[인프런 강의 복습] 스프링 핵심 원리 - 예제 만들기

■ 비즈니스 요구사항과 설계

1) 회원
- 회원을 가입하고 조회할 수 있다.
- 회원의 등급은 일반과 VIP가 존재
- 회원 데이터의 저장소는 아직 확정되지 않음

- 클라이언트, 회원 서비스, 회원 저장소 역할을 하는 인터페이스가 필요
- 회원 서비스에서는 회원 가입과 조회 역할을 한다.
- 회원 저장소는 DB 저장소, 메모리 저장소 등 저장소의 종류에 따라 다양한 구현체를 개발 할 수 있다.

2) 주문과 할인 정책
- 회원은 상품 주문이 가능
- 회원 등급이 따라 할인 정책이 적용
- VIP 등급은 1,000원 할인(고정 할인 정책 적용) 
- 할인 정책은 추후 변경될 수도 있다.

인터페이스를 만들고 구현체를 언제든지 갈아끼울 수 있도록 설계하는 것이 중요

 

■ 회원 도메인 개발(전체 코드가 아닌 중요한 코드만 삽입)

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 member1 = memberService.findMember(1L);
        System.out.println("new member = " + member.getName());
        System.out.println("find member = " + member1.getName());
    }
}
public interface MemberService {

    void join(Member member);

    Member findMember(Long memberId);
}
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);
    }
}
public interface MemberRepository {

    void save(Member member);

    Member findById(Long memberId);
}
import java.util.HashMap;
import java.util.Map;

public class MemoryMemberRepository implements MemberRepository {

    //동시성 이슈가 발생할 수 있다. 실무에서는 ConcurrentHashMap을 사용
    private static Map<Long, Member> store = new HashMap<>();   

    @Override
    public void save(Member member) {
            store.put(member.getId(), member);
    }

    @Override
    public Member findById(Long memberId) {
        return store.get(memberId);
    }
}

 

■ 회원 가입 테스트

JUnit을 이용해서 테스트

//given
//when
//then
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 원칙을 위배

 

■ 주문과 할인 도메인 개발(전체 코드가 아닌 중요한 코드만 삽입)

import soyeon.study.inflearn.member.Grade;
import soyeon.study.inflearn.member.Member;
import soyeon.study.inflearn.member.MemberService;
import soyeon.study.inflearn.member.MemberServiceImpl;
import soyeon.study.inflearn.order.Order;
import soyeon.study.inflearn.order.OrderService;
import soyeon.study.inflearn.order.OrderServiceImpl;

//주문 서비스 App
public class OrderApp {
    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        OrderService orderService = new OrderServiceImpl();
        Member member = new Member(1L, "memberA", Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(member.getMemberId(), "itemA", 10000);
        System.out.println("할인 가격 = " + order.calculate());
    }
}
import soyeon.study.inflearn.member.Member;
import soyeon.study.inflearn.member.MemberRepository;
import soyeon.study.inflearn.member.MemoryMemberRepository;

//OrderService의 구현체
public class OrderServiceImpl implements OrderService{
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final DiscountPolicy discountPolicy = new FixedDiscountPolicy();

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member findMember = memberRepository.findByMemberId(memberId);  //회원 조회
        //조회된 회원 정보를 통해 할인금액 조회
        int disCountPrice = discountPolicy.disCount(findMember);    

        return new Order(memberId, itemName, itemPrice, disCountPrice);
    }
}
import soyeon.study.inflearn.member.Grade;
import soyeon.study.inflearn.member.Member;

//할인 정책의 구현체
public class FixedDiscountPolicy implements DiscountPolicy{

    @Override
    public int disCount(Member member) {
        if(member.getGrade() == Grade.VIP){
            return 1000;
        }else{
            return 0;
        }
    }
}

 

[출처 : 인프런 스프링 핵심 원리 기본편]