Spring Boot/개념 정리

스프링부트 객체 지향 설계(2)_ 회원가입 예제

강하다이녀석 2023. 9. 3. 19:12

회원가입 예제

  • 요구사항에 있어서 정해지지 않은 부분이 많다면, 개발을 기획이 정해질 때까지 못하냐? →아님, 객체 지향 설계 방법을 활용하여, 인터페이스를 만들고 구현체를 언제든지 갈아끼울 수 있도록 설계할 수 있음!

요구사항 예시

| 회원 | 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);
    }
    //구현체

}
  • 지금 이 코드의 설계상 문제는 없나?
  • → 의존관계가 인터페이스 뿐만아니라 구현체까지 의존함