domain이라는 package를 만들고 Member 클래스를 생성하자.
Member 클래스에서는 회원의 정보가 담긴 클래스이다.

비즈니스 요구사항에서 정한 회원에 데이터는 Id와 이름이 있다.
Id는 회원이 직접 작성하는 값이 아닌, 데이터 구분을 위해서 시스템이 정한 Id이다. 코드는 아래와 같다.
package hello.hellospring.domain;
public class Member { // 비즈니스 도메인 객체, 데이터베이스에 저장하고 관리됨.
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
repository 라는 package를 생성하고 인터페이스로 MemberRepository를 생성한다.

현재 데이터베이스가 선정되지 않은 상화을 가정했기 때문에 우선 메모리 기반의 데이터 저장소를 사용하기로 했다. 추후에 저장소 교체를 더 용이하게 하기 위해 interface로 만든것이다. MemberRepository에 기능들을 만들어보자.
public interface MemberRepository { // 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
List<Member> findAll();
}
interface를 만들었으니 상속하는 구현체를 만들어보자.
repository package 안에 MemoryMemberRepository 클래스를 생성하고, MemberRepository를 상속한다. 그리고 메서드들을 override 해준다.
public class MemoryMemberRepository implements MemberRepository{
@Override
public Member save(Member member) { }
@Override
public Optional<Member> findById(Long id) { }
@Override
public Optional<Member> findByName(String name) { }
@Override
public List<Member> findAll() { }
}
메서드들을 구현하기 전에 필요한 변수들을 선언해야한다.
member들의 정보를 저장할 저장소가 필요하기 때문에 Map을 사용하고,
회원의 id값은 시스템에서 주는 값이기 때문에 회원이 가입했을 시 id를 부여해주어야한다.
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
이제 오버라이드 한 메서드들을 구현하자.
1. save
@Override
public Member save(Member member) {
member.setId(++sequence); // save시 시퀀스 올려줌
store.put(member.getId(), member); // 스토어에 저장
return member;
}
save는 Map에 member 객체를 저장하고 , 저장한 객체를 반환한다.
2. findById
@Override // 스토어에서 get을 사용하여 아이디 꺼냄 null이여도 반환가능하게 optional 사용
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
Id를 통해 member 객체를 찾는 메서드이다.
여기서 중요한 부분은 Optional 인데 return 값이 null일 가능성도 있다.
만약 null이 반환될 시 Null Pointer Exception이 발생하게 되는데, Optional.ofNullable 을 사용하여 에러발생을 막을 수 있다.
3. findByName
@Override // 루프를 돌면서 map에서 같은 이름의 네임을 찾는다
public Optional<Member> findByName(String name) {
return store.values().stream() // 루프를 돌려서
.filter(member -> member.getName().equals(name)) // 멤버에서 member.getName()이 파라미터로 받아온 name과 같은지
.findAny(); // 하나 찾아지면 찾은거 반환 null일 가능성 optional 사용
}
문자열 name을 받아 해당 name의 member 객체를 반환하는 기능이다.
stream을 사용하여 member 객체를 돌면서 member.getName이 paraemeter로 받은 name과 같은지 확인하고, 같은 경우에만 필터링한다.
findAny를 사용하여 결과가 있다면 return 을 하는데 여기 역시 null 값이 있을 수 있기 때문에 Optional을 사용한다.
4. findAll
@Override // values를 통해 전부 리턴 (values == 멤버들)
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
ArrayList를 생성하여 모든 값들을 담아 리턴한다.