섹션 2. 스프링 핵심 원리 이해1 - 예제 만들기(요구사항과 회원 도메인)

dev-mage·2022년 12월 28일
0
post-thumbnail
post-custom-banner

스프링 핵심 원리 - 기본편 - 인프런 | 강의

비즈니스 요구사항과 설계

요구사항

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

회원 도메인

회원 도메인 설계

  • 회원 도메인 협력 관계

  • 회원 클래스 다이어그램

  • 회원 객체 다이어그램
    • 서비스될 때 객체 간 메모리에서 실제로 어떻게 참조될지를 나타낸 것 ≠ 클래스 다이어그램

    • 생성된 인스턴스끼리의 참조를 나타낸다고 볼 수 있음

    • 구현체는 동적으로 할당되기 때문에 클래스 다이어그램으로 나타내지 않음

회원 도메인 구현

  • 회원
    • 회원 등급

      package hello.core.member;
      
      public enum Grade { BASIC, VIP }
    • 회원 엔티티

      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 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;
          }
      }
  • 회원 저장소
    • 회원 저장소 인터페이스

      package hello.core.member;
      
      public interface MemberRepository {
          void save(Member member);
      
          Member findById(Long memberId);
      }
    • 메모리 회원 저장소 구현체
      - 참고: HashMap은 동시성 이슈가 발생할 수 있음. 이런 경우 ConcurrentHashMap을 사용할 것

      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);
          }
      }
  • 회원 서비스
    • 회원 서비스 인터페이스

      package hello.core.member;
      
      public interface MemberService {
          void join(Member member);
      
          Member findMember(Long memberId);
      }
    • 회원 서비스 구현체

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

회원 도메인 실행과 테스트

  • 애플리케이션 로직으로(main 메서드에서 실행하는 것) 테스트하는 것은 좋은 방법이 아님.(콘솔에서 일일이 확인? → X) 테스트 프레임워크를 활용할 것
  • 회원 도메인 - 회원 가입 테스트
package hello.core.member;

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 foundMember = memberService.findMember(member.getId());

        // then
        Assertions.assertThat(member).isEqualTo(foundMember);
    }
}

회원 도메인 설계의 문제점

  • 위 코드는 설계상 문제점을 가지고 있음
  • 만약 메모리에서 다른 저장소로 변경하려고 하면 개방-폐쇄 원칙을 위배하게 됨
  • 의존성 역전 원칙 또한 위배
  • 이는 회원 서비스가 회원 저장소 인터페이스 뿐만 아니라 회원 저장소의 구현체까지 의존하고 있기 때문에 발생
    public class MemberServiceImpl implements MemberService {
        private final MemberRepository memberRepository = new MemoryMemberRepository();
    		...
    }
    • 개방-폐쇄 원칙: 기존 코드의 MemoryMemberRepository() 부분이 수정됨
    • 의존성 역전 원칙: MemoryMemberRepository() 에 의존
post-custom-banner

0개의 댓글