Purporse

Ensure that your model makes clear the distinction between things that we think of as describing (value objects) and things that have their own identities and lifecycles irrespective of the values of their attributes (entities).

Example

When discussing the value object pattern I will use Name as an example. In these examples Name represents a persons name and is made up of of FirstName/LastName/Title.

Validation

Value objects simplify validation noticably. An example of this would help so lets say that we have a Name class. A Name is made up of FirstName/LastName/Title and LastName/Title are required. There are several ways we could do this but we can consider two obvious solutions:
  1. Include get/set properties for all the parts of the the name on the Person class, significantly complicating this class and missing out an important part of the model.
  2. A Name class with get/set properties for FirstName/LastName/Title and an IsValid property that checks that LastName and Title are not null.
  3. A Name class that acts as a value object. The caller must provide atleast the LastName and Title and that validates that the two values are not null or String.Empty.
The advantage of the value object approach is that when validating a Person to ensure it has a Name we just need to ensure that it has an instance of the Name class because we know that if it has an instance then the instance must be valid.

Value Or Reference Type

In .NET you have a choice between using a struct or a class, in many cases in the example I've chosen a class for the following reasons:
  1. We don’t want people to be able to do use the default constructor that all classes have.
  2. NHibernate has problems mapping nullable custom structures, and although I like to practice persistence ignorance the reality is that at some point I will be mapping the domaim model to the database.
One disadvantage of using a class is that I have no choice about overriding Equals, where as with structs we only need to do it if performance requires it.

Persistence

The simple case is when the value object is made up of data in the same table that is populating the object that owns it, so if we have a Person table that contains all the data used to populate our Person class then it is easy to populate its Name using a <component> mapping.

We might instead have have a PersonName table with an identity column and have the Person table include a PersonNameID foreign key. If we did this then when we read in a Name and populate it from the PersonName table we must ensure that we store the id so that NHibernate can use it when deciding whether to write out the object again. The thing to be aware of here is that now replacing the Name means deleting a row from PersonName and then adding a new one.

If we had a PersonName table but its primary key was actually the persons ID then we have to be more careful. In particular with this approach if we replace a Person objects name with another one inside a single session then NHibernate will raise an exception because it won't be able to tell the two names apart (because both are of type PersonName and both have the same ID).

GUI

If we introduce a value object called Name to hold a persons name then the application code must ensure it creates new names rather than just updating the strings that make up a persons name. Design wise this is what we want but it is important to be aware of the way it changes any binding code.

In addition using value objects has an affect on the way the GUI finds out about validation failures. For example if we decided that our Name class is not a value object then we might have it expost a GetBrokenRules() collection that returns a list of broken rules that the GUI could display. However we can achieve the same goal by adding a static Validate method to the Name class which takes in the data and returns any reasons that the data cannot be used to produce a valid Name.

If we really want to get advanced we could look at the validation application block as the sort of extremely static non-state driven rules that value objects enforce could be nicely represented using attributes.

Links

http://wiki.moredesignpatterns.com/space/Value+Object
http://www.two-sdg.demon.co.uk/curbralan/papers/ValueAdded.pdf

Further Examples

Money

Last edited Aug 27, 2007 at 8:37 AM by colin_jack, version 21

Comments

No comments yet.