13 Nov 2023



Intermediate

Key characteristics of value objects in Domain-Driven Design (DDD) :

  1. Immutability: Value objects are typically immutable once created, ensuring their state doesn't change, maintaining consistency.

Examples:

  • Money Value Object: The Money value object represents a monetary amount with a specific currency. Immutability is maintained by not providing any setters for the amount and currency properties. Once a Money object is created, its state cannot be changed.

    public class Money {
        private final BigDecimal amount;
        private final Currency currency;
    
        public Money(BigDecimal amount, Currency currency) {
            this.amount = amount;
            this.currency = currency;
        }
    
        public BigDecimal getAmount() {
            return amount;
        }
    
        public Currency getCurrency() {
            return currency;
        }
    }
    
  • PhoneNumber Value Object: The PhoneNumber value object represents a phone number. Immutability is ensured by not providing any setters for the number property. Once a PhoneNumber object is instantiated, its value cannot be modified.

    public class PhoneNumber {
        private final String number;
    
        public PhoneNumber(String number) {
            this.number = number;
        }
    
        public String getNumber() {
            return number;
        }
    }
    
  1. Equality based on Value: Equality of value objects is determined by their internal state or values, not by identity. If two value objects have the same values, they are considered equal.

    Examples:

    • EmailAddress Value Object: The EmailAddress value object represents an email address. Equality is determined based on the address property. The equals and hashCode methods are overridden to compare and hash based on the email address.

      public class EmailAddress {
          private final String address;
      
          public EmailAddress(String address) {
              this.address = address;
          }
      
          @Override
          public boolean equals(Object obj) {
              // Implementation for equality based on 'address'
          }
      
          @Override
          public int hashCode() {
              // Implementation for hashing based on 'address'
          }
      }
      
    • Point Value Object: The Point value object represents a two-dimensional point. Equality is determined based on the x and y coordinates. The equals and hashCode methods are overridden accordingly.

      public class Point {
          private final int x;
          private final int y;
      
          public Point(int x, int y) {
              this.x = x;
              this.y = y;
          }
      
          @Override
          public boolean equals(Object obj) {
              // Implementation for equality based on 'x' and 'y'
          }
      
          @Override
          public int hashCode() {
              // Implementation for hashing based on 'x' and 'y'
          }
      }
      
  2. No Identity: Unlike entities, value objects don't have a distinct identity; they're identified by their attributes rather than a unique identifier. Examples:

    • Color Value Object: The Color value object represents an RGB color. It does not have a distinct identity; equality is based on the red, green, and blue components.

      public class Color {
          private final int red;
          private final int green;
          private final int blue;
      
          public Color(int red, int green, int blue) {
              this.red = red;
              this.green = green;
              this.blue = blue;
          }
      }
      
    • DateRange Value Object: The DateRange value object represents a range of dates. It does not have a distinct identity; equality is based on the startDate and endDate.

      public class DateRange {
          private final LocalDate startDate;
          private final LocalDate endDate;
      
          public DateRange(LocalDate startDate, LocalDate endDate) {
              this.startDate = startDate;
              this.endDate = endDate;
          }
      }
      
  3. Shared and Immutable: They're designed to be shared and reused across the domain model, promoting immutability to prevent unintended modifications. Examples:

    • Address Value Object: The Address value object represents a postal address. It is designed to be shared across entities and is immutable to prevent unintended modifications.

      public class Address {
          private final String street;
          private final String city;
          private final String zipCode;
      
          public Address(String street, String city, String zipCode) {
              this.street = street;
              this.city = city;
              this.zipCode = zipCode;
          }
      }
      
    • Country Value Object: The Country value object represents a country. It is designed to be shared and immutable, ensuring consistency across the domain model.

      public class Country {
          private final String name;
          private final String code;
      
          public Country(String name, String code) {
              this.name = name;
              this.code = code;
          }
      }
      
  4. Small-Scale and Coherent: They encapsulate a small set of related attributes that form a coherent whole, representing a specific concept within the domain.

    Examples:

    • Temperature Value Object: The Temperature value object represents a temperature with a specific unit. It encapsulates a small set of related attributes (value and unit) that form a coherent concept within the domain.

      public class Temperature {
          private final double value;
          private final TemperatureUnit unit;
      
          public Temperature(double value, TemperatureUnit unit) {
              this.value = value;
              this.unit = unit;
          }
      }
      
    • Duration Value Object: The Duration value object represents a time duration. It encapsulates a small and coherent concept related to time (seconds).

      public class Duration {
          private final long seconds;
      
          public Duration(long seconds) {
              this.seconds = seconds;
          }
      }
      
  5. Side-Effect-Free: Using value objects in operations or calculations does not produce side effects or change any external state.

    Examples:

    • Percentage Value Object: The Percentage value object represents a percentage. It is designed to be side-effect-free, meaning that using it in operations or calculations does not produce any unintended side effects.

      public class Percentage {
          private final double value;
      
          public Percentage(double value) {
              this.value = value;
          }
      }
      
    • Ratio Value Object: The Ratio value object represents a mathematical ratio. It is side-effect-free, ensuring that operations involving it do not produce any external side effects.

      public class Ratio {
          private final int numerator;
          private final int denominator;
      
          public Ratio(int numerator, int denominator) {
              this.numerator = numerator;
              this.denominator = denominator;
          }
      }
      
  6. Composability: Value objects can be combined to create more complex structures or as part of entity attributes.

    Examples:

    • GeoLocation Value Object: The GeoLocation value object represents a geographic location with latitude and longitude. It is composable, allowing it to be combined with other value objects, such as Point, to create more complex structures.

      public class GeoLocation {
          private final double latitude;
          private final double longitude;
      
          public GeoLocation(double latitude, double longitude) {
              this.latitude = latitude;
              this.longitude = longitude;
          }
      }
      
    • Dimensions Value Object: The Dimensions value object represents the dimensions of an object in three-dimensional space. It is composable, allowing it to be combined with other value objects, such as Point, to create more complex structures.

      public class Dimensions {
          private final double length;
          private final double width;
          private final double height;
      
          public Dimensions(double length, double width, double height) {
              this.length = length;
              this.width = width;
              this.height = height;
          }
      
      
      }