도메인 주도 설계 구현-엔터티(3)

도메인 주도 설계 구현

엔터티(entity)

엔터티의 발견과 그들의 내부적인 특징

분명하게 구분된 바운디드 컨텍스트의 유비쿼터스 언어는 도메인 모델의 설계에 필요한 개념과 용어를 제공한다.

엔터티와 속성을 알아내기

팀은 기술적이고 전술적인 모델링의 늪에 빠지길 원치 않는다

토론을 계속한 후에 팀은 단어를 만들어내여 요구사항에 더많은 의미를 부여해야 한다.

필수 행동 파헤치기

팀은 필수 특성을 식별한 후 필수 행동을 살펴 보게 된다.

언어를 올바르게 표현하기 위해 도메인 전문가와 용어를 통일시키고 해당 용어를 오퍼레이션화 시킨다.

역할과 책임

모델링의 한 측면은 객체의 역할과 책임을 발견하는 것이다.

여러 역할을 수행하는 도메인 객체

객체지향 프로그래밍에서 일반적으로 인터페이스는 구현 클래스의 역할을 결정한다.
올바르게 설계됐다면 클래스는 구현하는 각 인터페이스마다 하나의 역할을 갖는다.

만약 클래스에서 명시적으로 선언된 역할이 없다면 기본적으로 해당 클래스의 역할을 갖는다.

즉 클래스는 퍼블릭 메소드라는 암시적인 인터페이스를 갖고 있다.

클라이언트의 사용을 허가할 대상만 노출되도록 정확히 설계하고 그 이상은 노출시키지 말자

어떤 설계를 선택하더라도 유비쿼터스 언어가 기술적 선호보다 항상 우위에 서도록 하자.

생성

새로운 엔터티를 인스턴스화 할 때 이를 완전히 실별해 클라이언트가 찾을 수 있도록 충분한 상태 정보를 포착하는 생성자를 사용하길 바란다.

엔터티는 하나 이상의 고정자를 갖는다. 고정자는 엔터티의 전체 수명주기에 걸쳐 트랜잭션적 일관성이 유지돼야 하는 상태다.
생성이 성공적으로 이뤄지면 선언한 인스턴스 변수의 참조는 절대 null이 되지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.github.sejoung.ddd.chapter5;

import org.springframework.util.StringUtils;

public class User extends Entity {

private String userName;

private String password;

private String tenantId;

protected User(String userName, String password, String tenantId) {
this.setUserName(userName);
this.setPassword(password);
this.setTenantId(tenantId);

}

private void setUserName(String userName) {
if (StringUtils.isEmpty(userName)) {
throw new IllegalArgumentException("userName은 필수 값입니다.");
}
this.userName = userName;
}

private void setPassword(String password) {
if (StringUtils.isEmpty(password)) {
throw new IllegalArgumentException("password는 필수 값입니다.");
}

this.password = password;
}

private void setTenantId(String tenantId) {
if (StringUtils.isEmpty(tenantId)) {
throw new IllegalArgumentException("tenantId는 필수 값입니다.");
}
this.tenantId = tenantId;
}

@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
", tenantId='" + tenantId + '\'' +
'}';
}
}


클래스 설계시 자가 캡슐화가 얼마나 강력한지 보여준다.

복잡한 엔터티 인스턴스화를 위해선 팩토리를 사용하자

1
2
3
4
5
6
7
8
9
10
11

package com.github.sejoung.ddd.chapter5;

public class Tenant extends Entity {

public User registerUser(String userName, String password, String tenantId) {
return new User(userName, password, tenantId);
}
}


참조