OK, you’ve finally built up your beautiful platform agnostic
and persistent ignorant business domain layer.
It solves all of your business requirements and is elegant and
maintainable – too bad the model doesn’t fit nicely into your user interface!
This is about the time a non-domain driven developer says, “ha,
I told ya that domain model was a waste of time! You should have modeled your objects after
the user interface!” Was it really a
waste of time? Of course not! Well then how do we slap a UI on top of a
domain model? Chapter 11 of Jimmy Nilson’s
Applying Domain-Driven Design and
Patterns to the rescue.
Basically you have three options when hooking up a user
interface to your domain model:
- The
domain model hooks up directly to the UI, and it just happens to be a good
fit.
- You
wrap the domain model with a presentation specific object.
- You
map data from the domain model to a presentation specific object.
Of interest here are options 2 and 3. To keep the domain model clean and pure, it
may make sense to create a presentation specific object that transforms a
domain specific object into a user interface friendly one. The example given in Jimmy’s book is the one
where the domain model represents a name, first and last, as separate
fields. In the UI, the first and last
names are placed together in a single textbox.
Below I’ve provided an example of option #2, wrapping. In this example ResourceWrapper in the
presentation layer wraps a domain model Resource object. One thing that makes the UI easier to work
with is to flatten out object graphs like in this ResourceWrapper example,
specifically the resource’s manager.
public class ResourceWrapper
{
private Resource resource;
public ResourceWrapper(Resource resource)
{
this.resource = resource;
}
public string Name
{
get { return resource.FirstName + " " + resource.LastName; }
set
{
string[] names = value.Split(" ".ToCharArray(), 2);
resource.FirstName = names[0];
resource.LastName = names[1];
}
}
public string ManagerName
{
get { return new ResourceWrapper(resource.Manager).Name; }
set { new ResourceWrapper(resource.Manager).Name = value; }
}
public decimal Salary
{
get { return resource.Salary; }
set { resource.Salary = value; }
}
public Resource GetDomainObject()
{
return resource;
}
}
I have to write more code?
Yes, but you may be able to get around a lot of this by creating a
generic object to object framework that sets properties via reflection and/or
code generation. In the end, wrapping or
mapping domain objects sounds like a good idea when they just won’t fit nicely
into the UI.