[Spring]스프링 핵심 원리(기본편) - 2. 스프링 핵심 원리 이해(1)

Wooyong Jung·2023년 9월 7일
0
post-thumbnail
post-custom-banner
  • 해당 게시물은 인프런 "스프링 핵심 원리 - 기본편" 강의를 참고하여 작성한 글입니다.
  • 자세한 코드 및 내용은 강의를 참고해 주시길 바랍니다.
    강의링크 -> 스프링 핵심 원리 - 기본편 (김영한)

Section2. 스프링 핵심 원리 이해 - 예제 만들기

  • 주어진 요구사항을 토대로 설계에서 개발, 테스트까지 진행해보겠습니다.
  • 이번 예제에서는 스프링의 도움 없이 순수한 자바로만 개발합니다. 이는 요구사항이 변경됐을 때 유연한 대처가 가능한가 확인하기 위함입니다.
  • 이 프로젝트에서는 스프링부트를 설치하는데 이는 단지 프로젝트 환경설정의 편리성을 위함입니다.

📄 비지니스 요구사항과 설계

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

주문과 할인 정책
- 회원은 상품을 주문할 수 있다.
- 회원 등급에 따라 할인 정책을 적용할 수 있다.
할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
- 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루
고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)

요구사항을 확인해보니 확정되지 않은 사항들이 많음을 확인할 수 있습니다. 이는 인터페이스를 활용하여 객체 지향적으로 설계하면 될 것 같습니다.


📄 회원 도메인 설계 & 개발

회원 도메인 설계

Member 클래스 다이어그램입니다. 데이터 저장 위치가 아직 정해지지 않았다고 하니 MemberRepository 인터페이스를 구현하고 인터페이스를 상속받아 구현체를 개발합니다. 이 챕터에서는 데이터를 메모리에 저장하는 상황으로 가정MemoryMemberRepository를 구현하겠습니다.
MemberServiceImpl의 Impl에 대해 궁금해하실 수 있는데 인터페이스에 대한 구현체가 하나만 있는 경우 관례상 인터페이스명에 Impl을 붙여서 구현체 이름을 만든다고 합니다.

회원 도메인 개발

Member 엔티티입니다. Grade는 enum으로 BASIC, VIP가 있습니다.

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;
    }
    
    	... // getter and setter

MemberRepository 인터페이스입니다. 회원 가입, 조회 기능을 요구했으니 savefindById 메소드를 선언합니다.

public interface MemberRepository {
	void save(Member member);
 	Member findById(Long memberId);
}

MemberRepository를 상속받아 MemoryMemberRepository을 개발합니다. 같은 방법으로 MemberService 인터페이스를 구현하고 MemberServiceImpl을 개발하면 됩니다. 후에, DB 저장 위치가 확정돼도 다형성을 지키면서 유연하게 변경할 수 있을 것입니다.


📄 주문과 할인 도메인 설계 & 개발

주문, 할인 도메인 설계

주문과 할인 도메인 설계는 회원 도메인 설계에 비해 복잡합니다. 요구사항에서 할인정책은 변경될 수 있다고 했으니, 인터페이스로 구현하여 역할과 구현으로 구분해 줍니다. 전체적인 로직은 클라이언트가 주문을 생성하면 우선 MemberRepository에서 회원 조회를 통해 회원 등급을 확인합니다. 그 후 확인한 회원 등급을 갖고 DiscountPolicy에서 할인 금액을 반환합니다. 이후 OrderService는 할인 금액을 포함한 주문 정보를 반환합니다.

주문, 할인 도메인 개발

DiscountPolicy입니다. 할인 금액을 반환해 주는 역할인데 그 전에 회원의 등급을 확인해야하기 때문에 Member를 파라미터로 받습니다. 요구사항에서는 등급이 VIP인 경우에 1000원을 할인해 준다고 했으니 인터페이스를 상속받아 FixDiscountPolicy 구현체를 개발합니다.

public interface DiscountPolicy {
	int discount(Member member, int price);
}

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 and setter
 }

OrderService 인터페이스입니다.

public interface OrderService {
	Order createOrder(Long memberId, String itemName, int itemPrice);
}

OrderService 인터페이스를 상속받아 구현체를 개발할 때는 우선 memberRepository를 통해 Member 객체를 얻습니다. 그리고 얻은 Member 객체를 DiscountPolicy의 파라미터로 주어야 할인 금액을 얻을 수 있습니다.


스프링의 도움 없이 순수 자바 코드로 객체 지향의 특성을 최대한 지키면서 요구사항에 맞는 코드를 작성해 봤습니다. 그렇지만, 앞에서 배운 OCP, DIP를 잘 지키고 있다고 보기는 어렵습니다.

profile
실패를 두려워하지 않는 백엔드 개발자가 되기 위해 노력하고 있습니다.
post-custom-banner

0개의 댓글