posted on Friday, October 01, 2004 12:31 PM
by
mlorengo
Domain Modeling with The Virtual Cellar and Repositories
I did some initial modeling on the business domain for my Virtual Cellar
application. I was mainly focusing on two major classes. Producers of Wines
(Wineries) and Wines. Here's my initial set of requirements that I need to
model.
For the Producer
- A Producer has a Name
- A Producer has Contact Information consisting of an Address (including
City, StateOrProvince, PostalCode), Telephone Number, Fax Number, Email
Address and Website
- A Producer must produce anywhere from 1 to many distinct wines over the
Producer's existence
- A Producer can produce anywhere from 0 to many distinct wines per year
- A Producer can produce Wine made from 1 or More Varieties of Grape
For the Wine
- A Wine has a Name
- A Wine has a Vintage
- A Wine can have only 1 Region
- A Wine may have a Description
- A Wine is made from one or more grape Varieties
- A Wine may be designated as a Reserve, Estate Bottled, Estate Grown
etc...
By looking at these initial sets of attributes, I can think of some
other possible classes that I need.
Region
- A Region has a name
- A Region can contain one or more other Regions
- A Region may have a particular classification (DOC, DOCG, DO, DAO etc)
- A Region may have a Description
Varietal
- A Varietal has a name
- A Varietal may have a description
Based on the above initial set of rules, I've come up with the following
class diagram.

I'm unsure about a couple things on this picture, (I also got lazy and
neglected to make the private references available via public properties, just
assume that they are there for now).
- Should I break out the Address information into a separate class? Some
Producers may have multiple locations, such as a Tasting Room, or other
Corporate Locations. I don't think I'll do that for now, version 1 will only
support a primary location.
- I don't have any methods defined for these classes. I haven't described
some of the operations that I'll want to do with these classes, but at a
minimum I'll want to
Do CRUD operations on Wines available for a Producer
Do CRUD operations on Producers
Do CRUD operations on Regions and Varietals
How do I go about doing this? Well, I laid out my applications architecture
in
this post, So I see having an overall Manager class that provides
TableDataGateway objects which perform CRUD operations using coarse grained
(mainly classes in the business domain) interfaces. However, I've been reading a
couple of interesting
blog entries discussing different implementations of the
Repository
pattern.
Steve Maine presented a
VS2005
Solution demonstrating his implementation. I took that and created a class
diagram and sequence diagram so as to better illustrate his proposal. Please
read his most
excellent post before continuing.

His solution uses the generics enhancement in C# 2.0. This helps clean up the
coding around the RepositoryFactory which is responsible for getting a Class
Factory of the appropriate type. I have no problem with this.
The other interesting thing that he does is use Nested Classes to allow the
Repository Access to private Customer Key field. This means that you essentially
tie all these classes together in one class which can be a huge unwieldy mess.
To get around having on big .cs file he uses C# 2.0 Partial classes. Instead of
using Nested Clasess and C# 2.0 features, I think a better solution would be to
use the
internal modifier to make the field accessible to classes in the same
assembly.
After looking further at the code I did a quick Sequence Diagram, please let
me know if you find any errors (Right Click & Open in a New Window)...

There is only one thing that bothers me about this, and it may just be an
oversight (of course I could have misread it as well). It appears that a new
<Customer>Repository is getting created each time the GetRepository<>() method
is being called. Here's the code from his post...
public IRepository<T> GetRepository<T>()
{
IRepository<T> repository = null;
if( typeof( T ) == typeof( Customer ) )
{
repository = (IRepository<T>) new Customer.CustomerRepository( this );
}
else if( typeof( T ) == typeof( Address ) )
{
repository = (IRepository<T>) new Address.AddressRespository( this );
}
return repository;
} |
A better solution may be to cache the newly created instance in the
RespositoryFactory class so that it can be reused, rather than creating new
ones.
I like Jimmy Nilsson's approach as well. This corresponds more to the
TableDataGateway pattern I've been thinking about but adds a more cohesive (to
me) way of thinking about it. Most likely I'll use a synthesis of multiple
models for my implementation.
More on that later.
Update: Added link for Jimmy Nilsson's post