값 객체나, 엔티티 같은 도메인 객체에는 객체의 행동읠 정의할 수 있다.
예를 들어 사용장명으로 사욯라 수 잇는 문자열의 길이나 문자의 종류에 제한이 있다며 ㄴㅇ이런한 지식은 사용자명을 나타내는 값 객체에 정의할 수 있다.
근데 시스템에는 도메인 객체로 구현하기 어색한 행동도 있다. 도메인 서비스는 이런 어색함을 해결해주는 객체다.
예를 들어 사용자 이름 중복 여부 기능을 추가한다고 하자.
이 코드를 User 라는 도메인 객체에 추가하게 된다면 아래와 같이 할 수 있다.
class User {
private UserId id;
private UserName name;
public User(Integer id, String name) {
if (Objects.isNull(id) || Objects.isNull(name))
throw new ArgumentNullException();
this.id = new UserId(id);
this.name = new UserName(name);
}
public bool doesExist() {
// 중복 확인 코드
}
}
이 경우에는 사용자 객체가 자신의 중복여부를 스스로 질의해야한다.
User user = new User(1, "홍길동");
if (user.doesExist()) {
// do sth
}
결국 새로 생성된 객체가 스스로 중복되는 객체인지 검증을 해야하는 셈이다.
이런 경우에는 User 객체의 역할이 모호해지므로 "중복확인" 이라는 책임을 다른 객체에 넘겨주는 것이 좋다.
class UserService {
public boolean exist(User user) {
// 중복 확인 코드
}
}
UserService userService = new UserService();
User user = new User(1, "홍길동");
if (userSerivce.exist(user)) {
// do sth
}
하지만 도메인 서비스도 남용하게 되면 결코 좋지 않다.
도메인 객체를 단순히 데이터 저장을 위한 용도로 만들어버리기 때문이다. (빈혈객체? 라고 한다.)
빈혈 객체의 경우 해당 도메인 객체가 어떤 특성이 있는지 쉽게 파악하기 어려울 뿐더러,
데이터와 행위를 함께 모아 놓는다는 객체 지향 설계의 기본 원칙을 위배하는 것이다.
또 도메인에 관한 로직이 흩어지는 결과도 유발하기 때문에, 유연성이 저하된다.
따라서 도메인 객체에 정의하기가 정말 부자연스러운 코드들만 도메인 서비스로 분리해야한다.
물류 시스템의 도메인 서비스 예
1. 도메인 객체 설계
- 거점(운송허브, 중간 창고, 경유지 등이 될 수 있겠다)
- 배송되는 물건
2. 거점 엔티티 작성
: 한 거점에서는 입고와 출고가 일어날 수 있다. (재고관리의 측면)
class PhysicalDistributionBase {
// 출고
public Baggage ship(Baggage baggage);
// 입고
public void recieve(Baggage baggage);
}
하지만 "배송"이라는 행위는 거점 엔티티에 포함하기 쉽지 않은데, 아래처럼 적용했을 때
class PhysicalDistributionBase {
(...생략...)
public void transport(PhysicalDistributionBase to, Baggage baggage) {
Baggage shippedBaggage = this.ship(baggage);
to.recieve(shippedBaggage);
}
}
다음 목적지 거점의 행위를, 현재 거점에서 호출하고 있다는 점도 어색하고,
추가로 배송에 관한 로그 작업등의 코드가 필요하게 되었을 때 그 모든 행위의 책임을 현재 거점이 갖는다는 점에서
다루기 까다로워 질 수 있다.
따라서 운송 도메인 서비스를 정의해, 해당 역할과 책임을 맡기는 것이 더 바람직해 보인다.
class TransportService {
public void transport(PhysicaldistributionBase from, PhyysicalDistrbutionBase to, Baggage baggage) {
Baggage shippedBaggage = from.ship(baggage);
to.receive(shippedBaggage);
// 추가 필요한 코드
}
}
'책 > 도메인 주도 설계 철저 입문' 카테고리의 다른 글
[도메인 주도 설계 철저 입문] 6. 어플리케이션 서비스 - 도메인 서비스와의 분리! (0) | 2022.03.10 |
---|---|
[도메인 주도 설계 철저 입문] 5. 레파지토리 - 데이터와 관계된 처리를 분리하자 (0) | 2022.03.08 |
[도메인 주도 설계 철저 입문] 3. 엔티티 - 생애주기를 갖는 객체 (0) | 2022.03.07 |
[도메인 주도 설계 철저 입문] 2. "값 객체"의 개념 & 적용 예시 (0) | 2022.03.07 |
[도메인 주도 설계 철저 입문] 1. 도메인 주도 설계 읽게 된 이유 (0) | 2022.03.07 |