Entity vs Value Object - Phân Biệt Rõ Ràng¶
1. Khái Niệm Cơ Bản¶
Entity (Thực Thể)¶
Định nghĩa: Đối tượng có danh tính duy nhất và có thể thay đổi trạng thái theo thời gian.
Đặc điểm: - Có ID duy nhất - Có lifecycle (tạo → cập nhật → xóa) - Hai Entity giống hệt nhau về thuộc tính nhưng khác ID → vẫn là hai đối tượng khác nhau
Value Object (Đối Tượng Giá Trị)¶
Định nghĩa: Đối tượng không có danh tính, chỉ quan tâm đến giá trị và bất biến.
Đặc điểm: - Không có ID - Immutable (không thể thay đổi) - Hai Value Object có cùng giá trị → hoàn toàn giống nhau
2. So Sánh Trực Quan¶
| Tiêu Chí | Entity | Value Object |
|---|---|---|
| Identity | Có ID duy nhất | Không có ID |
| Mutability | Có thể thay đổi | Bất biến |
| Equality | So sánh theo ID | So sánh theo giá trị |
| Lifecycle | Tạo → Cập nhật → Xóa | Tạo → Sử dụng |
| Sharing | Không share | Có thể share |
3. Ví Dụ Thực Tế: Hệ Thống E-commerce¶
Entities¶
Order (Đơn Hàng)¶
Order #12345
- ID: ORD-12345
- Ngày tạo: 15/01/2024
- Trạng thái: PENDING → CONFIRMED → SHIPPED
- Khách hàng: Nguyễn Văn A
Tại sao là Entity?
→ Mỗi đơn hàng có ID riêng
→ Trạng thái thay đổi theo thời gian
→ Order #12345 ≠ Order #12346 (dù cùng sản phẩm)
Customer (Khách Hàng)¶
Customer #999
- ID: CUST-999
- Họ tên: Nguyễn Văn A
- Email: a@gmail.com → a.nguyen@gmail.com (có thể đổi)
- Địa chỉ: Hà Nội → TP.HCM (có thể đổi)
Tại sao là Entity?
→ Mỗi khách hàng có ID riêng
→ Thông tin cá nhân có thể thay đổi
→ Dù đổi tên, vẫn là cùng một người
Product (Sản Phẩm)¶
Product #ABC123
- ID: PROD-ABC123
- Tên: iPhone 15
- Giá: 25,000,000 VND → 23,000,000 VND (có thể đổi)
- Mô tả: "Smartphone cao cấp..." (có thể cập nhật)
Tại sao là Entity?
→ Mỗi sản phẩm có mã riêng
→ Giá và thông tin có thể thay đổi
→ Tracking được lịch sử thay đổi
Value Objects¶
Money (Tiền Tệ)¶
Money
- Amount: 250000
- Currency: VND
Tại sao là Value Object?
→ Không cần ID
→ 250,000 VND = 250,000 VND (hoàn toàn giống nhau)
→ Không thể "sửa" 250k thành 300k, phải tạo mới
→ Có thể dùng chung cho nhiều đơn hàng
Address (Địa Chỉ)¶
Address
- Street: "123 Nguyễn Du"
- District: "Quận 1"
- City: "TP.HCM"
- Country: "Vietnam"
Tại sao là Value Object?
→ Không cần ID riêng
→ Hai địa chỉ giống hệt = cùng một nơi
→ Không "sửa" địa chỉ, chỉ thay thế bằng địa chỉ mới
→ Nhiều khách hàng có thể cùng địa chỉ
Quantity (Số Lượng)¶
Quantity
- Value: 5
Tại sao là Value Object?
→ "5 cái" = "5 cái" (không có gì khác biệt)
→ Không cần tracking "5 cái nào"
→ Immutable: muốn từ 5 → 7, tạo Quantity mới
Email¶
Email
- Value: "user@example.com"
Tại sao là Value Object?
→ Email chỉ là một chuỗi ký tự
→ "user@example.com" = "user@example.com"
→ Không cần ID riêng cho mỗi email
→ Có validation logic (format, domain...)
4. Workflow Phân Biệt Entity vs Value Object¶
flowchart TD
A["Tôi có một đối tượng cần mô hình hóa"] --> B{Đối tượng này có<br/>cần tracking riêng?}
B -->|Có| C{Trạng thái có<br/>thay đổi theo thời gian?}
B -->|Không| D[" Value Object"]
C -->|Có| E[" Entity<br/>(có ID + lifecycle)"]
C -->|Không| F{Hai đối tượng cùng giá trị<br/>có giống nhau hoàn toàn?}
F -->|Có| D
F -->|Không| E
Câu Hỏi Tự Kiểm Tra:¶
- "Tôi có cần biết đây là cái NÀO không?"
- Có → Entity (ví dụ: Đơn hàng #12345)
-
Không → Value Object (ví dụ: 250,000 VND)
-
"Hai cái giống hệt nhau có khác biệt gì không?"
- Có → Entity (2 khách hàng cùng tên vẫn khác nhau)
-
Không → Value Object (2 số tiền 100k hoàn toàn giống nhau)
-
"Tôi có cần 'sửa' nó không?"
- Có → Entity (sửa thông tin khách hàng)
- Không → Value Object (thay số tiền, không sửa)
5. Ví Dụ Thực Tế: Hệ Thống Ngân Hàng¶
Entities¶
- Account (Tài Khoản): Mỗi tài khoản có số riêng, số dư thay đổi
- Transaction (Giao Dịch): Mỗi lần chuyển tiền có ID riêng để tracking
- Customer (Khách Hàng): Thông tin cá nhân có thể cập nhật
Value Objects¶
- Money: 500,000 VND (không cần ID)
- TransactionType: "TRANSFER", "DEPOSIT", "WITHDRAW" (enum)
- AccountNumber: "1234567890" (chỉ là chuỗi số)
- BankCode: "VCB", "TCB" (mã ngân hàng)
6. Common Mistakes (Lỗi Thường Gặp)¶
Lỗi 1: Làm Entity khi nên là Value Object¶
// SAI: Email không cần ID
class Email {
id: string; // Không cần!
value: string;
userId: string; // Không cần!
}
// ĐÚNG: Email chỉ là giá trị
class Email {
value: string;
isValid(): boolean {
// validation logic
}
}
Lỗi 2: Làm Value Object khi nên là Entity¶
// SAI: User cần có identity
class User {
name: string;
email: string;
// Không có ID → không tracking được
}
// ĐÚNG: User là Entity
class User {
id: UserId; // Cần ID!
name: string;
email: Email; // Email là Value Object
}
Lỗi 3: Value Object có thể mutate¶
// SAI: Value Object thay đổi được
class Money {
constructor(public amount: number) {}
add(other: Money) {
this.amount += other.amount; // Sai! Đang thay đổi
}
}
// ĐÚNG: Value Object immutable
class Money {
constructor(private readonly amount: number) {}
add(other: Money): Money {
return new Money(this.amount + other.amount); // Tạo mới
}
}
7. Best Practices¶
Cho Entity:¶
- Luôn có ID duy nhất
- Có lifecycle methods (create, update, delete)
- Kiểm soát state transitions
- Repository để persist/retrieve
Cho Value Object:¶
- Immutable (readonly properties)
- Validation trong constructor
- Meaningful methods (isValid, equals, toString)
- Có thể embedded trong Entity
Nguyên Tắc Chung:¶
- Favor Value Objects: Khi có thể, dùng Value Object (đơn giản hơn)
- Rich Domain Model: Value Object chứa logic, không chỉ data
- Consistency: Trong cùng Bounded Context, cùng khái niệm = cùng type
8. Kết Luận¶
Entity vs Value Object không phải về code, mà về business meaning.
- Entity: "Cái này là AI/CÁI GÌ cụ thể"
- Value Object: "Cái này GIÁ TRỊ BAO NHIÊU"