스프링을 이해하기 앞서 자바만을 가지고 코드를 짜보면서 어떤 구조가 나오는 지 확인해볼 것이다.
다음과 같은 요구사항을 줬다고 가정해보자.
- 회원을 가입하고 조회할 수 있다.
- 회원은 일반과 VIP 두 가지 등급이 있다.
- 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)
객체 지향에서 추상적 개념만 알고 있으면 실제 어떤 DB를 사용할 지 몰라도 상관 없으니 기본적인 설계를 짤 수 있다.
회원 클래스 다이어그램에서 정적으로 이론적인 움직임을 알 수 있고, 객체 다이어그램에서 실제 적용되는 구체적인 객체의 흐름을 나타냈다.
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);
}
}
MemberService로부터 상속받은 MemberServiceImpl 구현코드이다. 순수 자바로만 짠 코드인데 객체지향요소 SOLID를 잘 지켰는지 봐야한다.
이 코드의 설계상 문제점은 무엇일까요?
다른 저장소로 변경할 때 OCP 원칙을 잘 준수할까요?
DIP를 잘 지키고 있을까요?
: 의존관계가 인터페이스 뿐만 아니라 구현까지 모두 의존하는 문제점이 있음 주문까지 만들고나서 문제점과 해결 방안을 설명
memberRepository를 가져오는 부분을 보면 추상적 개념, 구체적 대상 모두 알고 있어야 함을 알 수 있다. 이는 OCP, DIP를 준수하지 못하는 코드였다.
주문과 회원 도메인 설계도 해보겠다.
주문과 할인 정책
- 회원은 상품을 주문할 수 있다.
- 회원 등급에 따라 할인 정책을 적용할 수 있다.
- 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
- 할인 정책은 변경 가능성이 높다.
- 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루 고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)
역할과 구현을 분리해서 자유롭게 구현 객체를 조립할 수 있게 설계했다. 덕분에 회원 저장소는 물론이고, 할인 정책도 유연하게 변경할 수 있다.
회원을 메모리에서 조회하고, 정액 할인 정책(고정 금액)을 지원해도 주문 서비스를 변경하지 않아도 된다. 역할들의 협력 관계를 그대로 재사용 할 수 있다.
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);
}
}
OrderServiceImpl 구현 코드이다. discount는 discountPolicy가 혼자 책임을 맡아 SRP는 잘 지켜지고 있다.
하지만 Repository, DiscountPolicy를 정하는 과정에서 다형성은 잘 유지하고 있지만 여전히 구체적인 객체를 알고 있어야 하는 치명적 단점이 있다. 이는 나중에 클라이언트의 요구사항 변경 시 큰 Overhead가 필요할 것이다.
이에 대해 스스로 어떻게 해결할 지 고민해보고 스프링을 이해하면 좋을 것 같다.
'BE Study > Spring' 카테고리의 다른 글
스프링 컨테이너와 스프링 빈 (0) | 2024.07.01 |
---|---|
객체 지향 원리 적용 (0) | 2024.06.29 |
객체 지향 설계와 스프링 (0) | 2024.06.28 |
회원 웹 기능- 등록 기능 구현하기 (0) | 2024.06.26 |
자바 코드로 직접 스프링 빈 등록하기 (0) | 2024.06.26 |