Spring 예제(2) 회원 도메인 설계 및 개발

woohee·2024년 3월 27일

Spring 핵심원리

목록 보기
4/12
post-thumbnail

🔖요구사항 설계를 기반으로 세부적으로 회원 도메인을 설계하고 개발해보자.

회원 도메인 설계

  • 회원 도메인 요구사항

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

회원 도메인 협력관계

회원 클래스 다이어그램

회원 객체 다이어그램

회원 서비스 구현 -MemberServiceImple

회원 도메인 개발

회원 클래스 다이어그램을 기반으로 개발!
member 파일 생성

  • Grade.java(enum)
  • member.java(javaclass)
  • MemberRepository.java(interface)
  • MemoryMemberRepository.java(javaclass -> interface 구현)
  • MemberService.java(interface)
  • MemberServiceImpl.java(javaclass ->interface 구현)

Grade.java

회원의 등급을 표시하는 enum
요구사항에 따라 회원은 BASIC, VIP로 나뉨

public enum Grade {
    BASIC,
    VIP
}

member.java

회원을 나타내는 객체
회원이 가지는 정보는 회원아이디, 회원이름, 회원등급이다.

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 Grade getGrade() {
        return grade;
    }

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

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

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

윈도우는 Alt+insert를 누르면 generate 기능을 활용하여 getter와 setter를 자동으로 완성해준다!

MemberRepository.java(interface)

회원 저장소 인터페이스이다.
인터페이스에서는 구현을 하지 않고 메서드 선언만 수행한다.
어떤 메서드가 필요할까?

  • 회원을 저장하는 메서드
  • 회원을 조회하는 메서드
public interface MemberRepository {
    void save(Member member);
    Member findById(Long memberId);
}

MemoryMemberRepository.java(interface 구현)

MemberRepository의 메서드를 구현하는 클래스이다.
해당 인터페이스가 가지는 메서드를 모두 구현해야 한다.
Map<>()을 사용하여 회원아이디와 이름을 저장할 것이다.
해쉬맵을 활용하여 회원 정보를 저장하고 조회하도록 구현해보자.

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.java(interface)

회원서비스 인터페이스이다.
인터페이스에서는 구현하지 않고 메서드만 선언해준다.
회원서비스에 필요한 메서드는 다음과 같다.

  • 회원 가입
  • 회원 조회
public interface MemberService {
    void join(Member member);
    Member findMember(Long memberId);
}

MemberServiceImpl.java(interface 구현)

MemberService 인터페이스를 구현하는 클래스이다.
해당 인터페이스가 가지는 모든 메서드를 구현해야 한다.
회원서비스를 이용하기 위해서는 회원 저장소 객체가 필요하다.
MemoryMemberRepository 객체를 생성하고
회원 가입을 하게 되면 저장해주고, 회원 조회를 하게 되면 저장된 회원 정보를 가져오자!

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

이렇게 회원 클래스 다이어그램대로의 코드 구현은 끝이 났다.
결과적으로 회원 객체 다이어그램대로 동작한다.
따라서 회원 클래스 다이어그램은 정적
회원 객체 다이어그램은 동적으로 표현된 다이어그램이다.
이제 실행과 테스트를 해보자 !

실행과 테스트

MemberApp.java를 생성하여 실행해보자.

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

실행결과는 new member와 find member가 똑같이 memberA로 출력될 것이다.

테스트 코드를 만들어서 실행해보자.


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

실행시켜보면 초록불이 들어올 것이다.
만약 findMember(2L)을 넣고 실행시키면 오류가 뜰 것이다.
이는 일치하지 않음을 뜻하고 테스트코드를 통해서 결과를 테스트할 수 있다.
요즘 개발자들은 테스트코드도 잘 작성할 줄 알아야 한다!

이렇게 개발해보면 인터페이스를 의존하는 것까지는 괜찮으나 문제는 구현체를 의존한다.
이는 SOLID 법칙을 위배하는 것이다.
순수 자바 코드로만 구현하였는데 SOLID 법칙을 위배했음을 확인했다.


📜Summary

  • 클래스 다이어그램은 정적, 객체 다이어그램은 동적 다이어그램이다.
  • 좋은 객체 지향 설계 방법에 근거하여 순수 자바 코드로만
    인터페이스를 설계하고 구현해도 SOLID 법칙을 위배한다.

0개의 댓글