스프링부트 객체 지향 설계(2)_ 회원가입 예제
회원가입 예제
- 요구사항에 있어서 정해지지 않은 부분이 많다면, 개발을 기획이 정해질 때까지 못하냐? →아님, 객체 지향 설계 방법을 활용하여, 인터페이스를 만들고 구현체를 언제든지 갈아끼울 수 있도록 설계할 수 있음!
요구사항 예시
| 회원 | 1.회원을 가입하고 조회할 수 있다. 2.회원은 일반과 VIP 두 가지 등급이 있다. 3.회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정) | | --- | --- | | 주문과 할인 정책 | 1.회원은 상품을 주문할 수 있다. 2.회원 등급에 따라 할인 정책을 적용할 수 있다. 3.할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.) 4.할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루 고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정) |
회원 도메인 협력 관계
- 회원데이터에 접근하는 계층을 따로 만든다.
- 위 셋이 역할이고, 밑에 있는 부분이 구현체→어떤 저장소를 쓰든 상관 없음.
- 인메모리 저장소를 연결해서 나중에 구현체만 갈아끼우면 된다
회원 클래스 다이어그램(정적
회원 객체 다이어그램(동적
- 실제 new한 인스턴스 참조
역할
package hello.core.member;
public interface MemberRepository {
void save(Member member);
Member findById(Long memberId);
}
구현체
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<>();
// hashMap의 경우 여러군데에서 접근하면 동시성 이슈가 있어서 ConcurrentHashMap을 쓴다.
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
역할
package hello.core.member;
public interface MemberService {
void join(Member member);
Member findMember(Long memberId);
}
구현체
package hello.core.member;
public class MemberServiceImpl implements MemberService {
// 추상화 뿐만 아니라 구현체에 의존하는 문제점. DIP위반!!!
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.회원을 가입하고 조회할 수 있다. 2.회원은 일반과 VIP 두 가지 등급이 있다. 3.회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정) | | --- | --- | | 주문과 할인 정책 | 1.회원은 상품을 주문할 수 있다. 2.회원 등급에 따라 할인 정책을 적용할 수 있다. 3.할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.) 4.할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루 고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정) |
회원 도메인 협력 관계
- 회원데이터에 접근하는 계층을 따로 만든다.
- 위 셋이 역할이고, 밑에 있는 부분이 구현체→어떤 저장소를 쓰든 상관 없음.
- 인메모리 저장소를 연결해서 나중에 구현체만 갈아끼우면 된다
회원 클래스 다이어그램(정적
회원 객체 다이어그램(동적
- 실제 new한 인스턴스 참조
역할
package hello.core.member;
public interface MemberRepository {
void save(Member member);
Member findById(Long memberId);
}
구현체
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<>();
// hashMap의 경우 여러군데에서 접근하면 동시성 이슈가 있어서 ConcurrentHashMap을 쓴다.
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
역할
package hello.core.member;
public interface MemberService {
void join(Member member);
Member findMember(Long memberId);
}
구현체
package hello.core.member;
public class MemberServiceImpl implements MemberService {
// 추상화 뿐만 아니라 구현체에 의존하는 문제점. DIP위반!!!
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.회원을 가입하고 조회할 수 있다. 2.회원은 일반과 VIP 두 가지 등급이 있다. 3.회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정) | | --- | --- | | 주문과 할인 정책 | 1.회원은 상품을 주문할 수 있다. 2.회원 등급에 따라 할인 정책을 적용할 수 있다. 3.할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.) 4.할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루 고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정) |
회원 도메인 협력 관계
- 회원데이터에 접근하는 계층을 따로 만든다.
- 위 셋이 역할이고, 밑에 있는 부분이 구현체→어떤 저장소를 쓰든 상관 없음.
- 인메모리 저장소를 연결해서 나중에 구현체만 갈아끼우면 된다
회원 클래스 다이어그램(정적
회원 객체 다이어그램(동적
- 실제 new한 인스턴스 참조
역할
package hello.core.member;
public interface MemberRepository {
void save(Member member);
Member findById(Long memberId);
}
구현체
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<>();
// hashMap의 경우 여러군데에서 접근하면 동시성 이슈가 있어서 ConcurrentHashMap을 쓴다.
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
역할
package hello.core.member;
public interface MemberService {
void join(Member member);
Member findMember(Long memberId);
}
구현체
package hello.core.member;
public class MemberServiceImpl implements MemberService {
// 추상화 뿐만 아니라 구현체에 의존하는 문제점. DIP위반!!!
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);
}
//구현체
}
- 지금 이 코드의 설계상 문제는 없나?
- → 의존관계가 인터페이스 뿐만아니라 구현체까지 의존함