[도메인 주도 설계 철저 입문] 5. 레파지토리 - 데이터와 관계된 처리를 분리하자
프로그램을 실행할 때, 메모리에 로드된 데이터는 프로그램을 종료하면 그대로 사라져버린다.
특히 엔티티는 생애주기를 갖는 개체이기 때문에 프로그램의 종료와 함께 사라지면 안된다.
이를 위해서는 데이터를 데이터스토어에 저장하고 불러올 수 있어야한다.
데이터스토어로부터 불러오고, 저장하는 등의 행위를 추상화한 객체가 레파지토리 객체이다.
레파지토리의 역할과 책임
이 레파지토리 객체는 도메인 개념으로부터 유래한 것이 아니라,
기술적 문제를 해결하기 위해 탄생한 객체이다.
따라서 도메인을 잘 서술한 코드를 헤집어놓지 않으면서, 기술적 코드를 잘 분리해는 역할을 담당한다고 볼 수 있다.
특히 특정 db 에 의존적일 수 밖에 없는데, 이 때문에 더 다루기 까다롭게 되는 코드가 되어버릴 때가 많다.
그래서 레파지토리 객체를 "불러오기 load(), 저장하기 save()" 등의 추상화한 행동으로 규정한 후
실제 기술적 코드는 레파지토리가 수행하고,
비지니스 로직에서는, 어떤 행동을 하는지만 쉽게 알 수 있다
레파지토리 인터페이스 정의하기
작은 프로젝트라면 하나의 db 만 사용할 수 있지만,
서비스 규모가 커지다 보면 여러 db 를 사용해야하는 경우가 생길 수 있다.
서비스 코드는 특정 인프라에 종속적이면 안되므로,
db 의 종류의 상관없이, 도메인 모델 객체를 저장,삭제,수정,불러오기 등의 추상화된 인터페이스를 제공하고,
db 종류에 맞게 구현된 구현체를 이용해야한다.
Interface repository {
void save(Entity entity);
void update(Entity entity);
void delete(Integer id);
Entity findById(Integer id);
}
Class MysqlRepository implements repository {
@Override
public void save(Entity entity) {
}
@Override
public void update(Entity entity) {
}
@Override
public void delete(Integer id) {
}
@Override
public Entity findbyId(Integer id) {
}
}
Class MongoRepository implements repository {
@Override
public void save(Entity entity) {
}
@Override
public void update(Entity entity) {
}
@Override
public void delete(Integer id) {
}
@Override
public Entity findbyId(Integer id) {
}
}
Class EntityService {
private final Repository repository;
public EntityService(Repository repository) {
this.repository = repository;
}
public Entity getEntity(Integer id) {
return repository.findById(id);
}
}
위와 같이 서비스와 레파지토리가 작성되어 있다고 하자
그러면 아래처럼 메인코드를 작성할 수 있다.
Repository repository = new MysqlRepository();
// Repository repository = new MongoRepository();
EntityService entityService = new EntityService(repository);
entityService.getEntity(1);
즉 비지니스 로직에서는 추상화된 레파지토리의 행동만 알면 되고,
구현체는 그때그때 필요한 것을 끼워 넣으면 되는 것이다.