When reasoning about business domains in projects with customers, domain objects and their services are always discussed. But if you listen more closely you might hear additional requirements on the domain. “Off course, customers can also find a book by typing in their ISBN” or “we also register the customer’s web site, by adding the URL.”
When to use value objects?
Both ISBN and URL have meaning to the customer’s domain. As most of us are aware, both types are stronger than just a character array in the database. This is when value objects become useful. A value object is a small and simple object, such as Isbn or Email that is meaningful to the customer domain, and is used for validation, often as type of properties of domain objects.
During a recent training I presented in Amsterdam (on UML), a software architect from the Dutch tax and customs administration (DTCA) explained that they hardly ever use base types such as int, string or even DateTime, but declare value objects for just about everything. His argument was that we know more about almost all domain object properties than that they’re just a string or a number.
Recipe for implementing value objects
My straightforward recipe for implementing a value object:
- Identify value object. Identify the value object you need, which is in most cases derived from the domain model. Give the new value object a proper name, such as Email, Password, or SubscriptionNumber.
- Represent value. Think of how the internal value for your value object can best be represented. In most cases a string will do just fine, otherwise DateTime is also a frequently used representation.
- Implement validations. Program the validations and checks required to validate whether a value presented is actually valid.
private static Regex Expression =
new Regex(@”^(?=.{13}$)\d{1,5}([-])\d{1,7}\1\d{1,6}\1(\d|X)$”);
public static bool IsValidIsbn(string newvalue)
{
return Expression.IsMatch(newvalue);
}
public Isbn(string newvalue)
{
value = null;
if (string.IsNullOrEmpty(newvalue)) return;
if (!IsValidIsbn(newvalue))
{
throw new FormatException(String.Format(“{0} is no ISBN”, newvalue));
}
value = newvalue;
}
- Consider null values. Consider if a null or an empty value should be allowed for your value object.
- Implement interfaces. Implement the proper interfaces for your value object, such as IComparable, and the generic interfaces IComparable to compare instances of your value object and IEquatable to see whether two instances are equal.
- Implement accessors. Implement any additional accessor methods your type requires, including the TryParse() pattern, but make sure your value object is immutable.
- Decide type. Consider whether your new type should be a value type or a reference type. This is largely depending on the size of the internal representation.
Benefits of value objects
There are validations to be met. Not all strings represent a valid ISBN or a valid URL. Although these well known examples are easily identified, quite often there are more hidden features of this kind that you might not notice at first glance, if you are not an expert in the specific business domain. Think of an employee number each new employee is associated with, or specific types of passwords.
Read more on implementing value objects
Last year I wrote a more elaborate article on implementing value objects. It was published in the Australian magazine Inernational Developer Magazine. Don’t hesitate to download the PDF at: Implementing value objects (PDF).
2 thoughts on “Implementing value objects”
Thanks for another valuable insight!
You’re very welcome.
Comments are closed.