I'm designing a new piece of software using ECO Modeler, which I will implement using ECO 2.
As I have been modelling the business classes I have been paying special attention to creating classes in patterns that I will be able to reuse in different applications.
PATTERN 1: Contact information
In the past I have said it, and I will say it again! Composition is more powerful than inheritance!
My contact information pattern is a good example of this. Different types of class often require some kind of contact information (telephone numbers, email addresses, etc). To save time reproducing classes many people will jump straight in and create a "Contact" class which has this various information. Then they will descend other classes such as [Company] and [Person] from this class.
I don't like this approach. Inheritance should be used when you want your implementation to treat objects in a common way, and not for the sake of reducing the amount of work you have to do when designing your model.
Take a [Booking] as an example. You may want to record various information in relation to a booking. Obviously the booking would have an association to a Person, but what if you wanted to keep historical contact information? The contact information for the person may change in the future, and then the historical information is lost. Do you make [Booking] a [Contact] too?
What if you want to record [Stock] locations? Would you descend [Van], [Room], [Building], [VendingMachine] from a common class? What if a [Person] can hold stock as well as hold contact information? Inheritance can be a real mess!
Instead I would create a set of classes as illustrated above. A [ContactInformationHolder] is responsible for holding contact information.
When I want a specific class to have a collection of [ContactInformation] I simply create a one-way association from the class (eg "Person") to the [ContactInformationHolder]. Using this approach I am able to make [Person] a holder of [Stock] AND also capable of holding numerous pieces of [ContactInformation].
PATTERN 2: Contact information - Country
I was trying to think up a reusable way to model a [PostalAddress]. Logically you should be able to determine which [Country] a [PostalAddress] belongs to, so my first instinct was to model an association from [PostalAddress] directly to [Country].
One of my customers didn't just want to know which country a person lived in, they wanted to categorise them by some kind of geographical region as well. Adding a [Region] association to the [Country] and [PostalAddress] seemed wrong to me. It would be possible to specify UK as the country, and a USA state as the region, I would have to include constraints to check for this. It just all seemed a bit messy.
So, I came up with this
Now instead of being associated directly to a [Country], a [PostalAddress] is actually associated to a [GeographicLocation]. This means that the [PostalAddress] can either belong directly to a [Country] for customers who don't want regions, or a [GeographicArea] for those who do.
In the above model it is possible to create a country that has many regions, and each of those regions may also have sub-regions. If a customer wanted they could categorise to a level as high as Country / State / City / Town.
The "Path" derived association merely returns a collection of [GeographicLocation], so that it is possible to display the full area as a string. So instead of "Acocks Green" (where I live) you could determine the area as "United Kingdom / England / West Midlands / Birmingham / Acocks Green".
So that I can easily determine the [Country] to which a [GeographicLocation] belongs I added another derived association. In the base class it is derived as "Country.emptyList". In the [Country] class it is derived as "self", and in the "GeographicArea" class it is derived as "self.parentArea.country".
PATTERN 3: Address
Finally, I was able to create an [Address] class to my satisfaction. I wouldn't need a common ancestor for my classes to have contact information, and my customers can either refer directly to a country, or to any level of geographical breakdown they wish.
My [Address] class simply has a PostalCode attribute, one or more [AddressLine] objects, and an association to a GeographicLocation.
- Hopefully these patterns will be generic yet flexible enough to use in any software application.