Chapitre 1 · Leçon 1
Les deux types fondamentaux d'objets en DDD
Section 1
Step 1
Une Entity est définie par son identité, pas ses attributs. Deux utilisateurs avec le même nom sont des entités différentes car ils ont des IDs différents. L'identité persiste dans le temps.
snippet.typescript
1// Entity — identité via l'ID
2abstract class Entity<T> {
3 protected readonly _id: T;
4
5 constructor(id: T) {
6 this._id = id;
7 }
8
9 get id(): T { return this._id; }
10
11 // Égalité basée sur l'ID
12 equals(other: Entity<T>): boolean {
13 return this._id === other._id;
14 }
15}
16
17// Entité User — son identité est son ID
18class User extends Entity<string> {
19 private _email: Email; // Value Object
20 private _name: FullName; // Value Object
21 private _role: UserRole;
22 private _events: DomainEvent[] = [];
23
24 private constructor(
25 id: string,
26 email: Email,
27 name: FullName,
28 role: UserRole,
29 ) {
30 super(id);
31 this._email = email;
32 this._name = name;
33 this._role = role;
34 }
35
36 // Factory method — validation dans la création
37 static create(props: CreateUserProps): User {
38 const id = generateId();
39 const email = Email.create(props.email); // peut lancer une erreur
40 const name = FullName.create(props.firstName, props.lastName);
41 return new User(id, email, name, 'viewer');
42 }
43
44 // Reconstitution depuis la persistence (pas de validation re-exécutée)
45 static reconstitute(data: UserData): User {
46 return new User(
47 data.id,
48 Email.reconstitute(data.email),
49 FullName.reconstitute(data.firstName, data.lastName),
50 data.role as UserRole,
51 );
52 }
53
54 // Méthode métier — émet un Domain Event
55 promoteToAdmin(): void {
56 if (this._role === 'admin') throw new DomainError('Déjà admin');
57 this._role = 'admin';
58 this._events.push(new UserPromotedToAdmin(this._id, new Date()));
59 }
60
61 get email(): string { return this._email.value; }
62 get fullName(): string { return this._name.full; }
63 get role(): UserRole { return this._role; }
64 get domainEvents(): DomainEvent[] { return [...this._events]; }
65 clearEvents(): void { this._events = []; }
66}Step 2
Un Value Object n'a pas d'identité propre — deux VO avec les mêmes attributs sont identiques. Ils sont immuables. Email, Adresse, Montant sont des Value Objects classiques.