Bỏ qua

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ị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:

  1. "Tôi có cần biết đây là cái NÀO không?"
  2. Có → Entity (ví dụ: Đơn hàng #12345)
  3. Không → Value Object (ví dụ: 250,000 VND)

  4. "Hai cái giống hệt nhau có khác biệt gì không?"

  5. Có → Entity (2 khách hàng cùng tên vẫn khác nhau)
  6. Không → Value Object (2 số tiền 100k hoàn toàn giống nhau)

  7. "Tôi có cần 'sửa' nó không?"

  8. Có → Entity (sửa thông tin khách hàng)
  9. 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"