반응형
# 예제 프로젝트 진행 (스프링 없는 순수 자바로만 개발 진행)
- 프로젝트 환경 설정을 편리하기 위해 스프링 부트 사용, 해당 예제 프로젝트는 스프링 없는 순수 자바로만 개발 진행.
- 역할(인터페이스) 구현(구현체) 나누어서 개발 진행.
- 필요 준비물 : Java 11 / IDE (IntelliJ or Eclipse)
## 프로젝트 생성
스프링 부트 스타터 이용 스프링 프로젝트 생성
- https://start.spring.io
- 아래와 같이 입력 및 선택하여 프로젝트 생성
Project : Gradle Project
Language : Java
Spring Boot : SNAPSHOR or M 붙지 않은 가장 최신 버전 선택.
Group : hello
Artifact : core (프로젝트 빌드명)
Packaging : Jar
Java : 11
Dependencies : 선택 없이 진행. (의존관계)
- GENERATE 로 압축 파일 내려받은 후 별도의 위치에 압축해제, 인텔리제이 실행해서 압축해제한 프로젝트 폴더 내 build.gradle 선택하여 프로젝트 실행.
- 설정이 모두 받아진 후 CoreApplication 실행하여 정상적으로 실행되는지 확인.
- 설정 변경 : Build and run using 과 Run tests using 을 IntelliJ IDEA로 변경. (윈도우의 경우 File -> Settings -> Gradle 입력)
## 비즈니스 요구사항과 설계
비즈니스 요구사항
1) 회원
- 회원 가입, 조회
- 회원 등급 존재 (일반, VIP)
- 회원 데이터 : 자체 DB 구축 or 외부 시스템과 연동 가능성. (미확정)
2) 주문과 할인 정책
- 회원은 상품 주문 가능.
- 회원 등급에 따라 할인 정책 적용.
- 할인 정책 : VIP는 1000원을 할인 (고정 금액 할인 -> 변경 가능성 존재, 미확정)
미확정된 부분 관련
- 역할과 구현을 분리 즉, 인터페이스와 구현체를 나누어 미확정된 부분에 대응할 수 있도록 함.
## 회원 도메인 설계
회원 도메인 요구사항
- 회원 가입, 회원 조회
- 회원 등급 존재 (일반, VIP)
- 회원 데이터 (자체 DB 구축 or 외부 시스템 연동 - 미확정)
회원 도메인 협력 관계
- 클라이언트 -> 회원 서비스 호출 (회원 가입 / 회원 조회 기능) -> 회원 저장소 생성 (인터페이스)
- 회원저장소(인터페이스) 의 역할(구현체)에 해당하는 메모리 회원 저장소, DB 회원 저장소, 외부 시스템 연동 회원 저장소 구현체 생성 (메모리 회원 저장소의 경우 재 시작 시 데이터 초기화(메모리 휘발성) 되므로 개발용도로 사용.
회원 클래스 다이어그램
- MemberService (인터페이스) - MemberServiceImpl (MemberService 의 구현체(구현 클래스))
- MemberRepository (인터페이스) - MemoryMemberRepository, DbMemberRepository (MemberRepository 의 구현체(구현 클래스))
회원 객체 다이어그램 (객체 간 참조)
- 클라이언트 -> 회원 서비스(MemberServiceImpl) -> 메모리 회원 저장소
## 회원 도메인 개발
- 인텔리제이 단축키 확인방법 : 윈도우의 경우 File -> Settings -> keymap 검색 해당 항목에서 찾고자 하는 항목 찾아서 사용하면 된다.
Grade
package hello.core.member;
public enum Grade {
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;
}
}
MemberRepository (인터페이스)
package hello.core.member;
public interface MemberRepository {
void save(Member member);
Member findById(Long memberId);
}
MemoryMemberRepository (MemberRepository 구현체)
package hello.core.member;
import java.util.HashMap;
import java.util.Map;
public class MemoryMemberRepository implements MemberRepository {
// 동시성 이슈로 인해 실무에서는 ConcurrentHashMap 사용 해야 함.
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 (인터페이스)
package hello.core.member;
public interface MemberService {
void join(Member member);
Member findMember(Long memberId);
}
MemberServiceImp (MemberService 구현체)
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);
}
}
## 회원 도메인 실행 및 테스트
- 위 작업 내역 정상 동작하는지 테스트.
테스트 방법1) 메인 메서드를 이용한 테스트 (좋은 방법 아님.)
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 memberA = new Member(1L, "memberA", Grade.VIP);
memberService.join(memberA);
Member findMember = memberService.findMember(1L);
System.out.println("member : " + memberA.getName());
System.out.println("findMember : " + findMember.getName());
}
}
테스트 방법2) Junit 테스트 프레임워크 이용.
- 테스트 코드 작성은 필수임. (반드시!)
- test 에 구조 동일하게 생성 하여 테스트 코드 작성.
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);
}
}
현재 회원 도메인 설계 문제점
- 다른 저장소 변경 시 OCP 원칙 준수?
- DIP 잘 지키고 있는지?
- 의존관계 문제. (MemberServiceImpl 에서 아래와 같이 MemberRepository 와 MemoryMemberRepository 모두 의존 중)
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
반응형
'인프런 강의 학습 > 스프링 핵심 원리(기본편)' 카테고리의 다른 글
재학습_객체 지향 원리 적용_1 (0) | 2022.09.02 |
---|---|
재학습_예제 프로젝트 진행_2 (0) | 2022.08.27 |
재학습_객체 지향 설계와 스프링 (0) | 2022.08.23 |
재학습_10일차 빈 스코프 (0) | 2022.02.18 |
재학습_9일차 빈 생명주기 콜백 (0) | 2022.02.17 |