Overview
Value Objects are immutable domain objects that are defined by their attributes rather than a unique identity. They represent descriptive aspects of the domain with no conceptual identity. Two value objects with the same attributes are considered equal.Key Characteristics
- Immutable: Once created, cannot be modified (use
frozen=True) - No Identity: Equality based on attributes, not ID
- Self-Validating: Validate on construction
- Side-Effect Free: Methods return new instances rather than modifying state
- Replaceable: Can be freely replaced with another instance of equal value
Value Object Structure
Value objects in Soft-Bee API follow this pattern:Real Example: Email Value Object
The Email value object demonstrates validation and behavior:src/features/auth/domain/value_objects/email.py.
Real Example: Password Value Object
The Password value object demonstrates complex validation:src/features/auth/domain/value_objects/password.py.
Value Object Design Principles
1. Immutability
Always usefrozen=True to prevent modification:
2. Validation
Validate in__post_init__ to ensure invalid objects cannot exist:
3. Equality
Implement__eq__ based on attributes, not identity:
4. Hashing
Implement__hash__ to allow use in sets and as dict keys:
5. String Representation
Provide a meaningful string representation:Creating a New Value Object
Step 1: Define the Value Object Class
Step 2: Add Behavior Methods
Step 3: Implement Equality and Hashing
Common Value Object Patterns
Single-Value Object
Simple wrapper around a single value:Multi-Value Object
Combines multiple related values:Enumeration Value Object
Restricted set of valid values:Measurement Value Object
Value with unit of measurement:Best Practices
Always Validate on Construction
Use Frozen Dataclasses
Return New Instances for Transformations
Implement Proper Equality
Protect Sensitive Data in String Representation
When to Use Value Objects
Use value objects when:- The concept has no unique identity
- Equality is based on attributes, not identity
- The value should be immutable
- The value has validation rules
- You want to encapsulate related attributes (e.g., coordinates)
- You want type safety (e.g.,
Emailinstead ofstr)
- The object needs to change over time
- The object has a lifecycle
- Identity matters (use an Entity instead)
Related Documentation
- Domain Entities - Mutable domain objects with identity
- Domain Exceptions - Validation error handling
- Domain Events - State change notifications