

김영한 Spring 기본편 강의 2 정리CS지식 및 수업 정리/spring2024. 4. 12. 11:58
Table of Contents
📖 비즈니스 요구사항 및 설계
- 회원가입 및 조회 기능
- 회원의 등급 - 일반/VIP, 등급에 따른 할인정책 적용, VIP는 1000원 할인
- 회원 상품 주문 가능
- 모든 할인 정책은 변경 가능성 높으므로 인터페이스와 구현체를 이용해 구현
📖 회원 도메인 설계
- 클라이언트가 회원 서비스를 호출하면 회원 서비스는 회원 가입, 회원 조회 기능을 제공
- 회원 데이터가 있는 저장소는 는 자체 db구축할지, 외부 시스템 연동할지 미확정이기 때문에 역할과 구현을 분리해 저장소를 무엇으로 할지 결정하면 그 구현체만 교체할 수 있도록 설계
📖 회원 클래스와 객체 다이어그램
- MemberService, MemberRepository : 회원 서비스와 회원 저장소라는 역할, 인터페이스 형태, 그 역할의 구현체는 클래스 형태의 구현체가 해준다.
- 클라이언트는 회원 서비스에 요청하고 회원 서비스는 회원 저장소에 요청
📖 Grade(enum)
package hello.core.member;
public enum Grade {
BASIC,
VIP
}
enum 자료형으로 Grade 등급 나눔
📖 회원 entity class
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 값(패키지 내 Grade enum 활용)
- 생성자 : id,name, grade 값 인수로 받아 초기화
- 메소드 : getter 및 setter 메소드들, 필드의 값을 반환 및 설정, intellij 내에서 alt+insert 단축키를 통해 자동으로 추가 가능
📖 MemberRepository(인터페이스)
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);
}
}
- MemberRepository의 인터페이스를 구현한 형태 중 메모리를 이용한 것, 인터페이스에서 정의된 메소드들 구현해야 함
- HashMap을 사용해 Member 객체를 메모리 상에 저장(프로그램 종료 시 소실),
- save 메소드 : 맴버 객체의 id를 키로 하고 맴버 객체 자체를 값으로 HashMap에 저장, store 필드는 HashMap 객체를 참조하는 변수
- findById : memberid 활용해 존재하면 멤버 객체 반환
📖 MemberService(인터페이스)
package hello.core.member;
public interface MemberService {
void join(Member member);
Member findMember(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 findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
- MemoryMemberRepository 의 객체를 참조
- join 메소드 : 외부에서 join 메소드가 호출될 때 memberRepository의 save 메소드를 활용해 메모리 저장소에 저장
- findMember : findById 활용
- 추가내용
📖 테스트
package hello.core.member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
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);
}
}
📖 현재 문제점
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
위 클래스는 클라이언트인데 멤버를 저장할 방식을 바꾸면 클라이언트 코드를 바꿔야함. OCP 원칙 위반, 또한 의존관계가 인터페이스 말고도 구현체에도 의존하게 되므로 DIP 원칙 위반
📖 Order 및 할인 도메인 설계
- 주문 생성: 클라이언트는 주문 서비스에 주문 생성을 요청한다
- 회원 조회: 할인을 위해서는 회원 등급이 필요하다. 그래서 주문 서비스는 회원 저장소에서 회원을 조회한다
- 할인 적용: 주문 서비스는 회원 등급에 따른 할인 여부를 할인 정책에 위임한다
- 주문 결과 반환: 주문 서비스는 할인 결과를 포함한 주문 결과를 반환한다
📖 주문 도메인 다이어그램
- 역할은 인터페이스, 구현체는 클래스를 통해 프로그램을 설계, 구현체가 하나일 경우 Impl을 붙였다
- 회원은 메모리나 db에서 조회하고 다른 할인 정책을 지원해도 역할과 협력 관계 그대로이다.
📖 DiscountPolicy(인터페이스)
package hello.core.discount;
import hello.core.member.Member;
public interface DiscountPolicy {
/**
* @return 할인 대상 금액
*/
int discount(Member member, int price);
}
📖 FixDiscouintPolicy 클래스(할인 정책 구현체 중 하나)
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
public class FixDiscountPolicy implements DiscountPolicy{
private int discountFixAmount = 1000; // 1000원 할인
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0;
}
}
}
📖 Order entity class
package hello.core.order;
public class Order {
private Long memberId;
private String itemName;
private int itemPrice;
private int discountPrice;
public Order(Long memberId, String itemName, int itemPrice, int discountPrice) {
this.memberId = memberId;
this.itemName = itemName;
this.itemPrice = itemPrice;
this.discountPrice = discountPrice;
}
public int calculatePrice() {
return itemPrice - discountPrice;
}
public Long getMemberId() {
return memberId;
}
public void setMemberId(Long memberId) {
this.memberId = memberId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public int getItemPrice() {
return itemPrice;
}
public void setItemPrice(int itemPrice) {
this.itemPrice = itemPrice;
}
public int getDiscountPrice() {
return discountPrice;
}
public void setDiscountPrice(int discountPrice) {
this.discountPrice = discountPrice;
}
@Override
public String toString() {
return "Order{" +
"memberId=" + memberId +
", itemName='" + itemName + '\'' +
", itemPrice=" + itemPrice +
", discountPrice=" + discountPrice +
'}';
}
}
- memberId, itemName, itemPrice, discoutPrice 등으로 구성된 Order
- calculatePrice : 실제 고객 지불할 금액 계싼
- toString : toString 클래스를 재정의해서 Order 객체의 정보를 쉽게 확인
📖 OrderService(인터페이스 )
package hello.core.order;
public interface OrderService {
Order createOrder(Long memberId, String itemName, int itemPrice);
}
📖 OrderServiceImpl
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
- 주문 생성 프로세스 처리
- 회원 ID, 상품 이름, 상품 가격 입력받으면 -> 회원 정보 조회 -> 할인정책 적용해 할인된 금액 계산 -> 정보 모두 포함해 새로운 Order 객체 생성
- MemoryMemberRepository와 FixDiscountPolicy 이용
'CS지식 및 수업 정리 > spring' 카테고리의 다른 글
Spring의존성 주입 @Autowired (0) | 2024.07.31 |
---|---|
김영한 spring 강의 3 (0) | 2024.05.03 |

@바이솔 :: Byesol의 기록