프로젝트 생성

스프링 프레임워크의 기능을 사용하지는 않을 거지만, 빠르게 프로젝트를 생성하기 위해 spring initializr를 통해 프로젝트를 생성한다.

조금 더 빠른 실행을 위해 IntelliJ 설정 > Gradle에서 빌드/테스트 실행 환경을 IntelliJ IDEA로 수정한다.

github remote repository 생성 후 해당 프로젝트를 연결했다.

# 프로젝트 디렉토리 루트 위치에서 실행
git init

# remote repository 설정(origin)
git remote add origin https://github.com/hongbre/spring-basic-1.git

# 사용 브랜치 master → main 변경
git branch -b main

# 변경 된 모든 파일 커밋 대상으로 추가
git add .

# 커밋 메시지와 함께 커밋
git commit -m "Project 생성"

# remote repository(github)에 push
git push origin main

비즈니스 요구사항

  • 회원
    • 회원을 가입하고 조회할 수 있다.
    • 회원을 일반과 VIP 두 가지 등급이 있다.
    • 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)
  • 주문과 할인 정책
    • 회원은 상품을 주문할 수 있다
    • 회원 등급에 따라 할인 정책을 적용할 수 있다.
    • 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용한다. (미확정)
    • 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고자 한다. 최악의 경우 할인을 적용하지 않을 수 있다. (미확정)

미확정인 회원 데이터 저장 방법, 할인 정책은 언제든지 변경 가능하도록 인터페이스로 구현할 필요가 있다.

회원 도메인 설계 및 개발

회원 도메인 클래스 다이어그램

회원 도메인 개발

회원 등급을 가진 enum 타입의 Grade와 회원 엔티티를 가진 Member 클래스를 생성한다.

public enum Grade {
    BASIC,
    VIP
}
public class Member {
    private Long id;
    private String name;
    private Grade grade;

    public Member(Long id, String name, Grade grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}

이후 MemberRepository 인터페이스를 생성하고, MemoryMemberRepository 구현 클래스를 생성한다.

public class MemoryMemberRepository implements MemberRepository {
    private static Map<Long, Member> store = new HashMap<>();
    ...
}

MemorymemberRepository에서 HashMap을 사용하고 있는데, 동시성 문제가 발생할 수 있으니 ConcurrentHashMap 사용을 권장한다고 한다. 이때 HashMap을 사용 할 때 동시성 문제가 발생하는 이유는 주로 여러 스레드가 동시에 맵을 수정하거나 접근할 때 발생하며, 데이터 무결성이 깨지는 문제이다. ConcurrentHashMap은 세그먼트 잠금(내부를 16개 세그먼트로 분할하여 부분적 잠금 사용), 원자적 메소드를 제공하여 복합 연상을 스레드 세이프하게 처리하는 등 스레드의 안전한 연산을 보장하고, Fail-Safe 반복자 사용으로 수정 중에도 안전하게 순회할 수 있다.

MemberService 인터페이스를 생성하고, MemberServiceImpl 구현 클래스를 생성, MemberApp를 생성해서 main 클래스를 추가해주는데 여기서 테스트를 진행하는 것은 바람직하지 못하니 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);
    }
}

가입한 member와 findMember로 찾은 멤버가 같으면 테스트는 성공한다.

public class MemberServiceImpl implements MemberService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    ...
}

여기서 문제가 있다면 Service 구현 클래스에서 인터페이스인 MemberRepository에도 의존하고, 구현 클래스인 MemorymemberRepository에도 의존하고 있다.

주문과 할인 정책 도메인 설계 및 개발

주문과 할인 정책 도메인 클래스 다이어그램

주문과 할인 정책 도메인 개발

memberId, itemName, itemPrice, discountPrice 4개의 속성을 가진 Order 클래스를 생성하고, OrderService 인터페이스와 OrderServiceImpl 구현 클래스 생성 및 DiscountPolicy 인터페이스와 FixDiscountPolicy 구현 클래스를 생성하게 된다. 동일하게 OrderApp 이라는 main 클래스를 추가해주었고, JUnit 테스트 클래스를 생성하였다.

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);
    }
}

memberA를 VIP 등급으로 회원 가입 시키고, 10000원짜리 itemA를 주문했을 때 할인 금액이 1000원이면 테스트는 성공한다.

'스터디 > Spring' 카테고리의 다른 글

Spring 스터디2 - 4  (1) 2025.04.17
Spring 스터디2 - 3  (0) 2025.04.13
Spring 스터디2 - 1  (0) 2025.03.23
Spring 스터디 - 7  (1) 2025.03.09
Spring 스터디 - 6  (0) 2025.02.18

+ Recent posts