Eiffel
  • Overview
    • About
  • Features
    • Cross cutting concerns
      • API response consistency
      • Global exception handling
      • Idempotency
      • Audit logging
    • Caching
      • Configuration
        • In-Memory
        • Redis
      • Usage
      • API
        • CacheSource
        • InMemoryCacheOptions
        • RedisCacheOptions
        • ICacheService
        • ICacheServiceFactory
    • Localization
    • Job Processing
    • Multi-Tenancy
    • Metrics & monitoring
    • Transactional outbox
      • PostgreSQL
      • MongoDB (cluster only)
    • Messaging
      • Kafka
      • Rabbit MQ
      • Azure Service Bus
    • Awaitable socket client
    • Graceful shutdown
  • Fundamentals
    • Persistence
    • Modelling
  • Principles
    • Domain-Driven Design
      • Aggregates
      • Entities
      • Value Objects
      • Domain Events
      • Factories
      • Domain Services
      • Business Identifiers
      • Shared Kernel
    • Onion Architecture
      • Application Layer
      • Domain Layer
      • Infrastructure Layer
      • Anti-Corruption Layer
    • Modular Monolith Architecture
      • Modules
      • Shared Infrastructure
    • Microservice Architecture
      • API Gateway
      • View Model Composition
      • Contracts
  • Business Aligment
    • Domain Storytelling
    • User stories
  • Implementation
    • Modular Monolith
    • Microservices
  • Testing
    • Unit Testing
    • Integration Testing
    • Contract Testing
  • Cloud Infrastructure
    • CI/CD Pipelines
    • Docker
    • Kubernates
    • Infrastructure as Code
Powered by GitBook
On this page
  1. Principles
  2. Domain-Driven Design

Value Objects

A Value Object represents a conceptually whole value with no identity. It is defined solely by its attributes or properties and is considered immutable, meaning its state cannot be changed after creation. Two Value Objects with the same attributes are considered equal, regardless of their individual identities.

Characteristics of Value Objects:

  1. Immutability: Once created, the state of a Value Object cannot be modified. Any changes to its properties result in a new Value Object instance.

  2. Equality based on attributes: Value Objects are compared based on the equality of their attributes rather than their identities.

  3. Side-effect-free: Value Objects should not have any behavior or actions associated with them. They are primarily used to hold and model data.

  4. Lightweight: Since Value Objects are immutable and do not have identities, they are typically lightweight and easy to copy.

  5. Replaceable: If two Value Objects have the same attributes, they can be replaced with each other without any impact on the domain logic.

Eiffel.Modelling.Abstractions NuGet package contains base ValueObject class. By using abstract ValueObject class you can define your value objects.

 /// <summary>
 /// Value object
 /// </summary>
 /// <typeparam name="T">The type of value object class</typeparam>
 public abstract class ValueObject<T> where T : ValueObject<T>
 {
     /// <inheritdoc/>
     public override bool Equals(object obj)
     {
         if (obj == null || GetType() != obj.GetType())
             return false;

         T other = (T)obj;
         return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
     }

     /// <inheritdoc/>
     public override int GetHashCode()
     {
         return GetEqualityComponents()
             .Aggregate(17, (current, obj) => current * 23 + (obj?.GetHashCode() ?? 0));
     }

     /// <inheritdoc/>
     protected abstract IEnumerable<object> GetEqualityComponents();
 }

Example Location value object.

public class Location : ValueObject<Location>
{
    public string City { get; }

    public string Country { get ;}

    public Location(string city, string country)
    {
        City = city;
        Country = country;
    }
}
PreviousEntitiesNextDomain Events

Last updated 1 year ago