[Spring-기본] 회원 도메인 설계(순수 자바로 만들기)

DANI·2023년 11월 21일

Spring[김영한T]

목록 보기
12/31
post-thumbnail

📂 새 프로젝트 생성

https://start.spring.io/

Generate 후 import 하기



✅ Settings > Gradle > IntelliJ로 변경





📑 비즈니스 요구사항 설계


📩 회원

  • 회원을 가입하고 조회할 수 있다.
  • 회원은 일반과 VIP 두 가지 등급이 있다
  • 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다(미확정)

📩 주문과 할인 정책

  • 회원은 상품을 주문할 수 있다.
  • 회원 등급에 따라 할인 정책을 적용할 수 있다.
  • 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용(나중에 변경 가능)
  • 할인 정책은 변경가능성이 높다. 기본 할인 정책을 아직 못 정했고, 오픈 직전까지 미룬다. 최악의 경우 할은을 적용하지 않을수도 있다.

회원DB와 할인 정책은 인터페이스를 만들고 구현체를 갈아 끼울 수 있도록 설계





회원 도메인 협력 관계




회원 클래스 다이어그램




회원 객체 다이어그램






🔴 클래스 다이어그램 구현해보기

💾 Member 클래스 생성

package hello.core.member;

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



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


}

💾 Grade Enum

package hello.core.member;

public enum Grade {
    Basic,
    VIP
}

💾 MemberRepository 인터페이스 생성 (save, findById)

package hello.core.member;

public interface MemberRepository {
    void save(Member member);
    Member findById(Long memberId);
}

💾 MemoryMemberRepository 구현

package hello.core.member;

import java.util.HashMap;
import java.util.Map;

public class MemoryMemberRepository implements MemberRepository{

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

💾 MemberService 인터페이스 생성 (join, findByMember)

package hello.core.member;

public interface MemberService {
    void join(Member member);
    Member findByMember(Long memberId);
}

💾 MemberServiceImpl 구현

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 findByMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}


💡 ctrl + shift + enter : ";" 까지 자동완성


✅ 회원 도메인 테스트 해보기

1. MemberApp 파일로 실행해보기

💾 MemberApp 파일 생성

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 service = new MemberServiceImpl();
        Member member = new Member(1L, "홍길동", Grade.VIP);
        service.join(member);
        Member member1 = service.findByMember(member.getId());
        if(member1.equals(member)){
            System.out.println("같은 객체 입니다");
        }else{
            System.out.printf("다른 객체 입니다");
        }
    }
}

🔴 실행결과

같은 객체 입니다

Process finished with exit code 0

2. MemberServiceTest로 실행해보기

💾 MemberServiceTest 파일 생성

package hello.core.member;


import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class MemberServiceImplTest {

    MemberService memberService = new MemberServiceImpl();

    @Test
    void join(){
        // given
        Member member = new Member(1L, "홍길동", Grade.VIP);

        // when
        memberService.join(member);

        // then
        assertEquals(member, memberService.findByMember(member.getId()));
        Assertions.assertThat(member).isEqualTo(memberService.findByMember(member.getId()));
    }
}

🔴 실행결과





🚫 구현의 문제점

  • 다른 저장소로 변경할 때 OCP원칙을 잘 준수할까?
  • DIP를 잘 지키고 있나?
    👉 구현체가 인터페이스뿐만 아니라 구현까지 모두 의존함


💡 해결방안

0개의 댓글