Skip to main content

Entities and Value Objects

Reading time: ~10 minutes

Introduction​

Entities and Value Objects form the foundation of the domain model in Prism Architecture. Located in the Core Layer, these elements represent the essential business concepts of your application. Understanding the distinction between these two types of domain objects is critical for building a robust domain model that accurately represents your business domain.

This document explains the key concepts of Entities and Value Objects, their characteristics, how they differ, and when to use each within the Prism Architecture.

Core Concepts​

What are Entities?​

Entities are domain objects that have a distinct identity that remains consistent throughout their lifecycle, even as their attributes change. They represent the "things" in your domain that have continuity and identity.

Key characteristics of Entities:

  1. Defined by Identity: Entities are primarily identified by a unique identifier rather than by their attributes. Two entities with identical attributes but different identifiers are considered different entities.

  2. Mutable or Immutable: Entities can be implemented either way, though immutability is often preferred when possible to promote predictability and prevent unexpected side effects.

  3. Continuous Identity: An entity remains the same entity even if all its attribute values change over time. A person is still the same person even if their name, address, and other attributes change.

  4. Lifecycle: Entities have a distinct lifecycle—they are created, they may change over time, and they may be archived or deleted.

  5. Business Rules: Entities often encapsulate business rules that govern their behavior and state changes. These rules help maintain the integrity of the entity.

Examples of Entities:

  • User/Customer
  • Order
  • Product
  • Account
  • Reservation

What are Value Objects?​

Value Objects are domain objects that have no identity of their own. They are defined entirely by their attributes and are used to describe, quantify, or measure aspects of the domain.

Key characteristics of Value Objects:

  1. Defined by Attributes: Value Objects are identified by the combination of all their attribute values. Two value objects with the same attributes are considered equal, regardless of their memory location.

  2. Immutable: Once created, their attributes should never change. If you need a different value, you create a new Value Object instance.

  3. No Identity: Value Objects don't have a unique identifier; they are interchangeable if they have the same attributes.

  4. Self-contained Validation: Value Objects validate their attributes upon creation to ensure they represent a valid concept.

  5. Conceptual Whole: They represent a complete concept in the domain, not just a primitive value.

Examples of Value Objects:

  • Money/Currency
  • Address
  • DateRange
  • Coordinates
  • PersonName
  • EmailAddress

Entities vs. Value Objects: Key Differences​

CharacteristicEntitiesValue Objects
IdentityDefined by identityDefined by attributes
MutabilityOften mutable, can be immutableAlways immutable
EqualityBased on identityBased on attribute values
LifecycleHas a distinct lifecycleNo independent lifecycle
ReplacementUpdated in placeReplaced entirely
ExamplesUser, Order, ProductMoney, Address, DateRange

Implementation in Prism Architecture​

Where Do They Fit?​

In Prism Architecture, Entities and Value Objects reside in the Core Layer, making them accessible to all other layers. This placement allows them to serve as the shared vocabulary for the entire application.

Entity Design Patterns​

Several design patterns can enhance your entity implementations:

  1. Typed Identifiers

Instead of using primitive types for entity IDs, use Value Objects to create type-safe identifiers. This approach prevents mixing up different types of IDs and makes the code more self-documenting.

  1. Entity Factory Methods

Create factory methods to enforce invariants during entity creation. Factory methods provide a clear and consistent way to create valid entity instances while encapsulating creation logic.

  1. Immutable Entities with Modification Methods

Implement entities as immutable structures with methods that return new instances when changes are needed. This pattern combines the benefits of immutability with the need to model entities that change over time.

Value Object Design Patterns​

Value Objects benefit from these design patterns:

  1. Factory Methods for Common Instances

Provide factory methods for commonly used instances to improve code readability and reduce duplication. For example, a Money class might offer factory methods for zero values or common currencies.

  1. Value Object Operations

Implement domain operations as methods on Value Objects. These operations create new Value Objects rather than modifying existing ones, respecting immutability.

  1. Value Object Conversion

Provide methods to convert between related Value Objects. For instance, a Temperature Value Object might include methods to convert between Celsius and Fahrenheit.

Common Patterns and Best Practices​

Entities Best Practices​

  1. Minimal Public API: Expose only methods that represent valid business operations.

  2. Encapsulate Business Rules: Business rules that govern state changes should be in the entity.

  3. Identity Generation Strategy: Be consistent with how entity IDs are generated (client-side vs server-side).

  4. Validation: Include validation logic for state changes, not just creation.

  5. Behavioral Focus: Focus on behavior over data storage.

  6. Persistence Ignorance: Entities should not know about how they are persisted.

Value Objects Best Practices​

  1. True Immutability: Ensure Value Objects cannot be modified after creation.

  2. Self-Validation: Validate all attributes during creation.

  3. Domain-Meaningful Operations: Implement methods that represent domain operations.

  4. Minimal Dependencies: Value Objects should have few or no dependencies.

  5. Clear Semantics: Choose names that clearly convey the concept represented.

  6. Equality by Value: Ensure equality compares all attributes.

Common Anti-Patterns to Avoid​

  1. Anemic Domain Model: Entities and Value Objects with no behavior, just getters and setters.

  2. Identity Confusion: Treating something with an ID as an Entity when it's conceptually a Value Object.

  3. Mutable Value Objects: Allowing Value Objects to change after creation.

  4. Primitive Obsession: Using primitive types instead of Value Objects for domain concepts.

  5. Overloaded Entities: Entities that try to do too much or represent too many concepts.

Entities and Value Objects in Other Layers​

While Entities and Value Objects are defined in the Core Layer, they interact with other layers in specific ways:

Domain Layer​

  • Uses Entities and Value Objects to implement business logic
  • May extend Entities with domain-specific methods
  • Validates operations on Entities using Value Objects

Orchestration Layer​

  • Coordinates operations on Entities
  • Manages the lifecycle of Entities
  • Maps between Entities and DTOs when needed

Infrastructure Layer​

  • Implements persistence for Entities
  • Converts between Entities and external data formats
  • Typically doesn't work directly with Value Objects except as part of Entities

Presentation Layer​

  • Displays Entity data to users
  • Formats Value Objects for display
  • Collects user input to create or modify Entities

Testing Entities and Value Objects​

Testing Entities​

  1. Identity Tests: Verify that equality works based on identity, not attributes.

  2. Behavior Tests: Test that business rules and methods work correctly.

  3. Lifecycle Tests: Ensure that an entity maintains its identity throughout state changes.

Testing Value Objects​

  1. Equality Tests: Verify that equality works based on all attributes.

  2. Validation Tests: Test that invalid states are rejected.

  3. Operation Tests: Test domain operations for correct results.

  4. Immutability Tests: Ensure that Value Objects cannot be modified after creation.

Real-World Examples​

Entity Example: Order​

An Order entity in an e-commerce system would have:

  • A unique OrderID that differentiates it from all other orders
  • Properties like customer information, shipping address, and line items
  • Methods for adding or removing items, applying discounts, or calculating totals
  • Business rules that enforce constraints like minimum order amounts or shipping restrictions
  • A distinct lifecycle from creation through processing, shipping, and fulfillment

Value Object Example: Money​

A Money value object in a financial application would have:

  • Properties for amount and currency
  • No identity—$10 USD is equal to any other $10 USD
  • Immutability—you don't change money, you exchange it for different money
  • Operations like addition, subtraction, or percentage calculation
  • Validation to ensure proper initialization with valid currency and amount

Conclusion​

Entities and Value Objects form the foundation of a robust domain model in Prism Architecture. By correctly identifying which concepts should be Entities and which should be Value Objects, you create a domain model that accurately reflects your business domain and provides a solid foundation for the rest of your application.

The Core Layer's accessibility to all other layers makes these domain concepts a shared vocabulary throughout your application, ensuring consistency and reducing the need for translation between layers.

By following the patterns and best practices described in this document, you'll create Entities and Value Objects that not only represent your domain concepts accurately but also enforce business rules, maintain data integrity, and support the clear separation of concerns that is central to Prism Architecture.

Next Steps​

  • Domain Services - Learn how to implement business logic that operates on entities
  • Repositories and Data Access - Understand how to persist and retrieve entities
  • Use Cases and Business Logic - See how entities and value objects are used in use cases