icon

KE Programmer

Entities and Value Objects in Domain Driven Design
Published on Feb 02, 2024 14:47 by KE Programmer

Table of Contents

1. Introduction

Two common concepts that one will encounter in Domain Driven Design are entities and value objects.

2. Examples

A person could be represented as an entity, whereas their name is a value object.

In a financial transaction, the transaction is represented as an entity and is stored in perpetuity, whereas the amount involved is a value object composed of an number and a currency unit.

3. Explanation

An entity is a long lived object in the domain that has an identity, whereas a value object is a characteristic of an entity without an identity of its own. A value object is its data. Two value objects with the same data are the same thing.

Let us consider a person named Jack Ma . Jack Ma will always remain a unique individual throughout their lifetime. If he changes his first name to John, his identity doesn't change even though his name did.

Two different people may be named Jack Ma, and as value objects, their names are equal. However the people who have these names are considered different entities.

4. Sample Code

In Python we can represent value objects using immutable objects like named tuples or frozen dataclasses.

>>> from collections import namedtuple
>>> Name = namedtuple('Name', 'first_name', 'last_name')
>>> Name('John', 'Ma') == Name('Jack', 'Ma')
False
>>> Name('John', 'Ma') == Name('John', 'Ma')
True

Entities can be represented as mutable objects that are composed of value objects. Even if two different entities may have similar characteristics, each is unique.

>>> class Person:
...   def __init__(self, name):
...     self.name = name
...
>>> person1 = Person(Name('Jack', 'Ma'))
>>> person2 = Person(Name('Jack', 'Ma'))
>>> person1.name == person2.name
True
>>> person1 == person2
False

Entities can be assigned a unique id that is then be stored in the database, so that it is persistent across restarts or in distributed applications. The dunder method __eq__ can be overridden to help with equality operations on these entities.

class Transaction:
  def __init__(self, uid):
    self.uid = uid

  def __eq__(self, other):
    if not isinstance(other, Transaction):
      return False
    return self.uid == other.uid

>>> t1 = Transaction(1)
>>> t2 = Transaction(2)
>>> t1_other = Transaction(1)
>>> t1 == t2
False
>>> t1 == t1_other
True