I received an interesting question recently: is an enum an entity or a value object?

1. The Enumeration pattern

Let’s start with defining an enum. An enumeration (enum for short) is a type that contains all possible values of that type. The simplest example in C# is this:

public enum Grade
{
    A = 0,
    B = 1,
    C = 2,
    D = 3
}

For simple situations, a simple enum is fine, but in more complex ones, it’s better to introduce a custom class to avoid switch statements like this being scattered across the whole code base:

public int GetNumberOfPoints(Grade grade)
{
    return grade switch
    {
        Grade.A => 10,
        Grade.B => 8,
        Grade.C => 4,
        Grade.D => 2,
        _ => throw new ArgumentException()
    };
}

You can avoid this by putting all the relevant switch statements into the custom enumeration class:

public class Grade
{
    public static readonly Grade A = new Grade(0, "A");
    public static readonly Grade B = new Grade(1, "B");
    public static readonly Grade C = new Grade(2, "C");
    public static readonly Grade D = new Grade(3, "D");

    public int Id { get; }
    public string Name { get; }

    private Grade(int id, string name)
    {
        Name = name;
        Id = id;
    }

    public int GetNumberOfPoints()
    {
        if (this == A)
            return 10;

        if (this == B)
            return 8;

        if (this == C)
            return 4;

        if (this == D)
            return 10;

        if (this == A)
            return 2;

        throw new ArgumentException()
    }
}

Or, alternatively:

public class Grade
{
    public static readonly Grade A = new Grade(0, "A", 10);
    public static readonly Grade B = new Grade(1, "B", 8);
    public static readonly Grade C = new Grade(2, "C", 4);
    public static readonly Grade D = new Grade(3, "D", 2);

    public int Id { get; }
    public string Name { get; }
    public int NumberOfPoints { get; }

    private Grade(int id, string name, int numberOfPoints)
    {
        Name = name;
        Id = id;
        NumberOfPoints = numberOfPoints;
    }
}

This pattern is call the Enumeration pattern.

2. Entity vs Value Object

Now, the question is: how would you categorize a domain class like that? Is it an entity or a value object?

I wrote about the differences between entities and value objects a while back in this article: Entity vs Value Object: the ultimate list of differences. But here’s a short summary in one image:

The most important difference between entities and value objects is the Id field. Entities have an Id, while value objects don’t. All other differences are mere implications of this one.

3. Is Enumeration an Entity or Value Object?

So, is an enumeration an entity or value object?

This is a tricky question, given that in the first implementation (as a C# enum), the Grade didn’t have have an Id, but now (as a custom class) it does.

Enumerations is where the line between entities and value objects gets blurred, but here’s how I would categorize them:

  • Enumerations with 1 field are value objects

  • Enumerations with more than 1 field are entities

One-field enumerations act as value objects because you can treat their instances interchangeably as long as their content is the same.

Conversely, instances of such enumerations are not the same if any of their fields don’t match, which is exactly how value objects behave:

// This class is a value object
public class Grade
{
    public static readonly Grade A = new Grade("A");
    public static readonly Grade B = new Grade("B");
    public static readonly Grade C = new Grade("C");
    public static readonly Grade D = new Grade("D");

    public string Id { get; }

    public Grade(string id)
    {
        Id = id;
    }
}

public void SomeMethod()
{
    // grade1 and grade2 are not the same
    var grade1 = new Grade("A");
    var grade2 = new Grade("B");
}

On the other hand, two Grade instances in the following example are the same, even though they have different contents:

// This class is an entity
public class Grade
{
    public static readonly Grade A = new Grade("A", 10);
    public static readonly Grade B = new Grade("B", 8);
    public static readonly Grade C = new Grade("C", 4);
    public static readonly Grade D = new Grade("D", 2);

    public string Id { get; }
    public int NumberOfPoints { get; }

    public Grade(string id, int numberOfPoints)
    {
        Id = id;
        NumberOfPoints = numberOfPoints;
    }
}

public void SomeMethod()
{
    // grade1 and grade2 are the same
    var grade1 = new Grade("A", 10);
    var grade2 = new Grade("A", 8);
}

Of course, in a real code base, you don’t want to instantiate Grade like this. You want its constructor to be private, so that its clients refer to its instance using the static fields only.

But this is still a good thought experiment, which helps us understand whether the class behaves like an entity or a value object.

Even if we could create 2 different A grades, they would still conceptually be the same grade, despite the NumberOfPoints being different. That’s because they have the same Id field (A). This is exactly how entities behave: we compare them using their Ids with no regard for other fields.

--Vlad

https://enterprisecraftsmanship.com


Enjoy this message? Here are more things you might like:

Consulting and training — I offer consulting and group training for organizations on Unit Testing and Domain-Driven Design. Reply to this email with the word "consult" to discuss.

Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »

My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »