이번에는 스프링을 최대한 안쓰면서 개발을 진행했다.
일단 버전은 Java11에 2.7.14 버전으로 스프링을 generate를 했다. 다른 dependencies는 아무것도 설정하지 않았다.
비지니스 요구사항은
아직 DB나 할인 정책은 미확정이므로 인터페이스를 만들고 구현체를 바꿔낄 수 있게 끔 개발을 진행한다.
일단 hello.core에 member라는 패키지를 만든다.
패키지안에 Grade 이름으로 Enum 클래스를만든다. (Enum클래스를 이용해서 해당 클래스 내에 있는 값만 값을 들어오게할수있다.)
package hello.core.member;
public enum Grade { // 열거형 클래스
BASIC,
VIP
} // BASIC, VIP 라는 값만 들어올 수 있음
그 후 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 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;
}
}
요구사항에 맞게끔 id, name, grade 변수를 만든다. (Enum 클래스를 통해서 grade에는 BASIC or VIP 값만 들어올 수 있음)
이제 회원 저장소를 만든다. 아직 DB가 확정이 아니기에 인터페이스를 만든뒤 구현체를 만들어서 진행한다. (추후에 구현체를 바꿔낄수 있게끔)
MemberRepository 인터페이스 생성
package hello.core.member;
public interface MemberRepository {
void save(Member member); // 회원 저장
Member findById(Long memberId); // 회원의 아이디 찾기
}
인터페이스 생성 후 해당 인터페이스를 상속받는 MemberRepository 클래스 구현
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<>(); // 동시성이슈가 있기에 실무에서는 ConcurrentHashMap 이용
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
이제 회원 서비스를 만들어야한다
마찬가지로 인터페이스를 만들고 클래스를만들어서 역할과 구현을 나누자
MemberService 인터페이스를 만든다.
package hello.core.member;
public interface MemberService {
void join(Member member);
Member findMember(Long memberId);
}
이제 마찬가지로 MemberSerice 인터페이스를 상속받는 MemberServiceImpl를 만들어야한다.
package hello.core.member;
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
// 인터페이스를 의존하고 할당하는부분이 구현체를 의존한다. DIP 위반하고 있는거여서 변경할때 어려움이 있다.
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
해당 실행이 잘 작동하는지 확인하기 위해 CoreApplication에 같은 경로에 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 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());
}
}
이렇게 자바를 돌리면서 테스트를 할 수 있지만 실행결과를 눈으로 확인을 해야하는 번거로움이 있다. 그래서 이번에 테스트 코드로 테스트를 확인해본다.
test로 가서 member패키지를 생성한 후 MemberServiceTest를 만들어서 테스트를 실행한다.
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 findMember = memberService.findMember(1L);
//then
Assertions.assertThat(member).isEqualTo(findMember);
}
}
해당 회원 도메인 같은경우 DIP를 잘 지키지 않고 있다. 위 주석에 있는 부분이 인터페이스 뿐만 아니라 구현까지 모두 의존하는 문제점이 존재한다.
'JAVA & SPRING > Spring 핵심원리-기본' 카테고리의 다른 글
스프링 핵심 원리 - 5일차 (컴포넌트 스캔) (0) | 2023.07.29 |
---|---|
스프링 핵심 원리 - 4일차(싱글톤 컨테이너) (0) | 2023.07.28 |
스프링 핵심 원리-3일차(AppConfig로 OCP, DIP 원칙 준수) (0) | 2023.07.26 |
스프링 핵심 원리 기본편-2일차(스프링 핵심원리 이해1 - 주문 & 할인 도메인) (0) | 2023.07.24 |
스프링 핵심 원리 기본편 - 1일차(스프링 이론, 스프링은 왜 만들어졌을까) (0) | 2023.07.24 |