Design Question

Design Question

Old forum URL: forums.lhotka.net/forums/t/2137.aspx


cultofluna posted on Saturday, January 13, 2007

Hello,

I have a design question regarding the correct way to handle a two layer editable object structure. I have an app that uses two bo's: customer and customerContact. One customer can have multiple customerContacts.
During the use of the application the user most of the time makes selections of customerContacts so a readonly list does the trick there.
The problem lies with editing the customerContact's. In the book Rocky mentions that an invoiceline is nothing without an invoice. In a way that's also the case with customerContact's, they are nothing without a customer. This means however, for maintenance on customerContact's I always have to load an editable customer BO and an editable collection with customerContact BO's, even when only a small modification has to be made to a customerContact.

My questions:

Is it wrong to simply make the customerContact an editable rootobject?

Is it handy to use ReadOnly BO's as criteria parameters, like for a new customerContact a customer ReadOnly BO is used as criteria and for editing a customerContact ReadOnly BO?

Or even making new customerContact's only available using a NewContact method from the customer ReadOnly BO and editing customerContact's only using an Edit method from the customerContact ReadOnly BO?

Any thoughts?

SonOfPirate replied on Saturday, January 13, 2007

So, if I am understanding you correctly, you have a one-to-many relationship between a customer and a contact (so that a customer can have many contacts but a contact can only belong to one customer)?

Not sure what you meant by having "to load an editable customer BO and an editable collection with customerContact BO's, event when only a small modification has to be made to a customerContact", but let me describe how I've addressed this.  I am interested in other's comments as well as this was an under-explained scenario in the book, IMO.

I would have a Customer object with a read-only child collection, CustomerContactList, containing read-only CustomerContactInfo child objects.  In the form used to edit the Customer object, you would display the list of CustomerContactInfo objects in a list or grid view.  To edit a contact's information, you would open another form that is bound to the editable root CustomerContact object.

The trick is in how the CustomerContact object is instantiated.  If you are editing an existing item, then it is simply a matter of telling the second form the unique identifier for the item to edit - everything else, including the relationship with the Customer is already established.  For a new item, you have a few options.

First, expose a CreateContact() method from your Customer class.  This will allow you to instantiate the object and pre-set the Customer object as the parent.  The new object would then be passed to and bound to the second form.

Another option is to pass the unique identifier of the parent Customer to the second form which then instantiates the new object passing the identifier to the constructor, i.e. Contact newContact = Contact.NewContact(customerID).

A third option, which works when you have many-to-many relationships, is to have a Contact editable root object that can be instantiated and edited on it's own then add the new object to the Customer's ContactList which will establish the relationship.  Again, this is more suited for many-to-many scenerios which it doesn't sound like you are doing.

As I said, I am interested in other's feedback on this as well because I certainly don't know that my approach(es) are the only or best options out there.

HTH

 

RockfordLhotka replied on Saturday, January 13, 2007

Why wouldn't you have read-only CustomerContactList and CustomerContactInfo objects and then have an editable root CustomerContactEdit object? It sounds like that combination would accomplish your goal. The user can see and select from that read-only list, and an edit dialog (or whatever) can pop up to allow the user to edit a specific contact.

cultofluna replied on Tuesday, January 16, 2007

Hello,

The most important rule is that a Customer has to have at least one Contact. The problem is that I have two goals for the BO's:

1. Background processing where my online information is imported to my local system. The import is not allowed to succeed when one of the BO's are invalid.

2. Application, where the users create a new Customer and add Contacts. There is only one moment where information is saved to the database.

For this a solution is needed where both the Customer and Contact are BusinessBases?! What I meant with"to load an editable customer BO and an editable collection with customerContact BO's, event when only a small modification has to be made to a customerContact" is that when I only want to change for example the firstname of a Contact I would need to load the Customer AND the Contact. However with Rocky's solution this would be a less expensive operation, but than again if I want to support both goals the Contact BO must be switchable, which in my opinion isn't a pretty solution.

There are to many options here :)

RockfordLhotka replied on Tuesday, January 16, 2007

The key to success is to design your objects for each use case independantly. You are describing at least three use cases (background-import, user-creates-customer and user-adds-contact), at least as I understand what you are saying.

You should only try to reuse objects across use cases if their responsibilities match exactly - after you've designed them for each use case.

In other words, design your set of objects for background-import. That means defining their responsiblity, listing their behaviors and collaborators. Do the same for user-creates-customer and user-adds-contact - each one as a totally separate set of objects from the others.

Then you can look across all three (or n) use cases to see if you have objects with the same responsiblity/behavior description in different use cases. If so, you can choose to reuse that object. If not, then you can't.

Regardless, you should always look for behaviors that appear in multiple objects, within or across use cases. These duplicate behaviors should be normalized into a centralized class, and the objects where they originally appeared should then collaborate with this new object/class to gain access to those behaviors. This, in my view, is the primary way you get reuse out of OOD. Not at the object level, but at the behavior level.

Copyright (c) Marimer LLC