Reputation: 8085
I am working on a project where I am wrestling with trying to move from one persistence pattern to another.
I've looked in Patterns of Enterprise Application Architecture, Design Patterns, and here at this MSDN article for help. Our current pattern is the Active Record pattern described in the MSDN article. As a first step in moving to a more modular code base we are trying to break out some of our business objects (aka tables) into multiple interfaces.
So for example, let's say I have a store application something like this:
public interface IContactInfo
{
...
}
public interface IBillingContactInfo: IContactInfo
{
...
}
public interface IShippingContactInfo: IContactInfo
{
...
}
public class Customer: IBillingContactInfo, IShippingContactInfo
{
#region IBillingContactInfo Implementation
...
#endregion
#region IShippingContactInfo Implementation
...
#endregion
public void Load(int customerID);
public void Save();
}
The Customer class represents a row in our Customer Table. Even though the Customer class is one row it actually implements two different interfaces: IBillingContactInfo, IShippingContactInfo.
Historically we didn't have those two interfaces we simply passed around the entire Customer object everywhere and made whatever changes we wanted to it and then saved it.
Here is where the problem comes in. Now that we have those two interfaces we may have a control that takes an IContactInfo, displays it to the user, and allows the user to correct it if it is wrong. Currently our IContactInfo interface doesn't implement any Save() to allow changes to it to persist.
Any suggestions on good design patterns to get around this limitation without a complete switch to other well known solutions? I don't really want to go through and add a Save() method to all my interfaces but it may be what I end up needing to do.
Upvotes: 0
Views: 2103
Reputation: 7656
You can easily add a Save()
method constraint to the inherited interfaces by simply having IContactInfo
implement an IPersistable
interface, which mandates the Save()
method. So then anything that has IContactInfo
also has IPersistable
, and therefore must have Save()
. You can also do this with ILoadable
and Load(int ID)
- or, with more semantic correctness, IRetrievable
and Retrieve(int ID)
.
This completely depends on how you're using your ContactInfo
objects though. If this doesn't make sense with relation to your usage please leave a comment/update your question and I'll revisit my answer.
Upvotes: 0
Reputation: 4363
How many different derivatives of IContactInfo
do you plan to have?
Maybe I'm missing the point, but I think you would do better with a class called ContactInfo
with a BillTo
and a ShipTo
instance in each Customer
. Since your IShippingContactInfo
and IBillingContactInfo
interfaces inherit from the same IContactInfo
interface, your Customer
class will satisfy both IContactInfo
base interfaces with one set of fields. That would be a problem.
It's better to make those separate instances. Then, saving your Customer
is much more straight-forward.
Are you planning on serialization for persistence or saving to a database or something else?
Using a concrete type for Customer and ContactInfo would definitely cover the first two.
(A flat file would work for your original setup, but I hope you aren't planning on that.)
I think it all comes down to how many derivatives of IContactInfo you expect to have. There is nothing wrong with a bit more topography in your graph. If that means one record with multiple portions (your example), or if that is a one-to-many relationship (my example), or if it is a many-to-many that lists the type (ShipTo, BillTo, etc.) in the join table. The many-to-many definitely reduces the relationships between Customer and the various ContactInfo types, but it creates overhead in application development for the scenarios when you want concrete relationships.
Upvotes: 1