In this demo we want to do some fractional arithmetic. A fraction is an example for an entity that represents a defined value on the one hand but has structure on the other: numerator and denominator. Even more interesting: two fractions looking different can be equal, such as: 1/3 == 2/6
.
Here we want to apply the Value Object Pattern to introduce a small simple object, like money or date range, whose equality isn't based on identity (Fowler).
A Fraction is an immutable tuple of numerator and denominator.
Every operation on a Fraction instance that would modify it, instead creates a new Fraction instance.
Open ValueObjectTest.java to start playing with this pattern. By setting the log-level for this pattern to DEBUG in logback.xml you can watch the pattern working step by step. Take a look, how equality of Fraction is defined (equals(), hashCode(), compareTo()
).
- Identity Field, Money and also Null Object are value objects.
- Records simplify implementing ValueObjects in Java.
- The above Fraction implementation shows a common pitfall when defining equality deviating from the representational state. If you put 1/3, 2/6 and 4/12 into a
HashSet
, it will afterwards contain just a single entry. - A family of Value Objects can be found in the collider package: KeyAtPos, CountingKeyCollision, TrackingKeyCollision, AnonymousCountingKeyCollision, AnonymousTrackingKeyCollision. These objects simplify sorting and processing because they define a natural order.
- (Fowler) Fowler, M.: Patterns of Enterprise Application Architecture. Addison-Wesley (2002)