[도메인 설계]
1. 도메인 협력 관계 : 기획자들도 볼 수 있음.
2. 클래스 다이어그램 : 도메인 협력 관계를 바탕으로 개발자들이 구체화해서 클래스 다이어그램을 만듦.
실제 서버를 실행하지 않고 클래스들만 분석해서 볼 수 있음.근데 DB뭘 넣을 지는 서버가 뜰때 결정되는 동적.
3. 객체 다이어그램 : 서버가 떠서 클라이언트가 실제로 사용하는 인스턴스끼리의 참조.
[회원 도메인 개발]
<enum>
public enum Grade{
BASIC,
VIP
}
<Member>
public class Member{
private Long idl
private String name;
private Grade grade;
public member(Long id, Strong name, Grade grade){
this.id = id;
this.name = name;
this.grade = grade;
~get, set으로 private 값 세팅할 수 있도록~
}
<MemberRepository> - (회원 저장소) 리포지터리 인터페이스
public interface MemberRepository {
void save(Member member); //저장 기능
Member findById(Long memberId); //찾는 기능
}
<MemoryMemberRepository> - 리포지터리 구현체
@Component
//MemberRepository 구현체
public class MemoryMemberRepository implements MemberRepository{
//저장소 만들기
private static Map<Long,Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
//저장소에서 가져와서 id찾기
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
cf. private static Map<Long,Member> store = new HashMap<>();
여러곳에서 store에 접근하면 동시성의 문제가 있을 수 있어 ConcurrentHashMap을 사용권함
<MemberService> - 인터페이스
public interface MemberService {
void join(Member member); //가입
Member findMember(Long memberId); //찾기
}
<MemberServiceImpl> - 구현체
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository; //가입하고 찾기 위해->생성자 만들고
public void join(Member member) {
memberRepository.save(member); //-> 다형성에 의해 인터페이스(memberRepository)가 아니라
//MemoryMemberRepository의 save()가 호출됨.
}
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
private final MemberRepository memberRepository = new MemoryMemberRepository;
구현체 없이 null 이면 exception-> 구현 객체 선택
다형성에 의해 인터페이스가 아니라 MemoryMemberRepository에 있는 save가 호출(추상화와 구현 모두에 의존..그러면 안됨)
<MemberApp>
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 FindMemner = memberService.findmember(1L):
}
}
<MemberApp> 은 스프링 없이 순수 자바로 테스트 -> jUnit를 사용함 : <MemberServiceTest>
<MemberServiceTest>
join한거랑 찾은거랑 같은지 눈으로 출력하는 system.out이 아닌 Assert통해서 빠르게 확인가능
public class MemberServiceTest {
MemberService memberService = new MemberServiceImpl();
@BeforeEach
public void beforeEach(){
AppConfig appConfig=new AppConfig();
memberService= appConfig.memberService();
}
@Test
void join(){
//given ~주어졌을때
Member member=new Member(1L,"membera",Grade.VIP);
//when ~이렇게 했을 때
memberService.join(member);
Member findMember=memberService.findMember(1L); //찾아서 then에서 검증
//then ~이렇게 된다
Assertions.assertThat(member).isEqualTo(findMember);
}
}
여기까진 DI위반 중
[주문과 할인 도메인]
<DiscountPolicy> - 인터페이스
public interface DiscountPolicy {
//return:할인대상금액
int discount(Member member,int price);
}
<FixDiscountPolicy> - 정액할인 구현체
public class FixDiscountPolicy implements DiscountPolicy{
private int discountFixAmount=1000; //1000원 할인
@Override
public int discount(Member member, int price) {
if (member.getGrade()== Grade.VIP){ //enum은 ==으로 사용
return discountFixAmount;
}else{
return 0;
}
}
<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;
}
~Getter&Setter 작성
//객체를 출력하면 toString으로 나와
@Override
public String toString() {
return "Order{" +
"memberId=" + memberId +
", itemName='" + itemName + '\'' +
", itemPrice=" + itemPrice +
", discountPrice=" + discountPrice +
'}';
}
}
<OrderService> - 주문서비스 (주문 결과 반환)인터페이스
public interface OrderService {
Order createOrder(Long memberId, String itemName, int itemPrice);
//주문생성시 파라미터를 넘겨 return으로 반환한다.
}
<OrderServiceImpl> - 주문서비스(주문 결과 반환) 구현체
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);
}
}
주문생성 요청이 오면 회원정보를 먼저 조회하고 할인정책에 회원을 넘겨서 최종 생성된 주문을 반환
OrderService는 할인에 대해 몰라 discountPolicy가 알아서해줘~->단일체계 원칙을 잘 지킴
<OrderApp>
public class OrderApp {
public static void main(String[] args) {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member); //메모리 객체에 넣어놓고
Order order = orderService.createOrder(memberId, "itemA", 10000);
System.out.println("order = " + order);
}
}
주문테스트 main메서드에서 테스트함. 스프링 없이 순수 자바로 테스트 -> jUnit를 사용함 <OrderServiceTest>
<OrderServiceTest> - 주문테스트 자동화된 테스트
class OrderServiceTest {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
@Test
void createOrder() {
long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000); //검증!
}
}
'Spring 강의 > springMVC' 카테고리의 다른 글
springMVC 기본 - (5) 싱글톤 컨테인너 (0) | 2022.03.11 |
---|---|
springMVC 기본 - (4) 스프링 컨테이너와 빈 (0) | 2022.03.10 |
springMVC 기본 - (3) 객체 지향 원리 적용 (0) | 2022.03.10 |
springMVC - IoC, DI, 컨테이너 (0) | 2022.03.09 |
springMVC 기본 - (1) 좋은 객체 지향 설계와 스프링 (0) | 2022.03.06 |