Hi Ted,
Here’s my opinion (hey, you did ask for it!):
I believe the kinds of inheritance being suggested here are all the wrong way to model it. It is almost always better to model an association as “has-a” rather than “is-a”. (keep reading to see what I mean by that)
I, personally, avoid inheritance in the EOModel if at all possible. Not because it is bad or hard to work with, but because in most cases it is not the *right* thing to do. Just like if I write non-UI code that uses “instance of” I know that I’m almost certainly doing something wrong. Not always, but often enough that I will stop and take a step back and REALLY look at how it is architected.
If you model the Person/Client correctly you will have no problem with how to model the relationship to Address. That issue will solve itself.
Okay, let’s get started:
Except Clients tend to be businesses with EINs instead of SSNs. So there really are Clients.
Bzzzzzt. Tend to be?! If you are going to use a structure as inflexible as inheritance on this they MUST ALWAYS BE, or there must be a very important business rule that keeps them separate. Is it really true that you never, ever, ever have a client that is just one guy and he doesn’t have an EIN? Or have a Person that has a relationship to other People? Those are perfectly legitimate concepts, yet you are forcing it to not be workable.
I think being a client is a role that an Object has (has-a) not what it is (is-a). Sometimes it acts like a “Client", at other times it could act like a “Vendor” and maybe, just maybe, if the Organization is a very simple one, it acts like a “Person"
I think Marcus’ suggestion of LegalEntity is great, I’ve also used “Actor” in the past. “Entity" would be ideal, but well, that’s a bit overloaded here in WOWorld! :-)
But! Instead of extending LegalEntity with subclasses for Person, Client, Vendor, WOGod, etc. You have a “Role” table that has one row for each of those. Now instead of a LegalEntity needing to be (is-a) one *and only one* of those subclasses, it can take-on any (has-a) Role (LegalEntity <<=> Role)s or even have multiple *simultaneous* roles (LegalEntity <<=>> Role)! So a Person could also be a Client and would have all the attributes and behaviors of both.
This allows your to abstract away all the behaviors and such that are Person-specific, Client-specific or Vendor-specific to delegate classes for each Role. The delegate classes are where you have the role-specific implementations.
For example, LegalEntity's method taxIdentifier() simply asks the delegate for the value.
public String taxIdentifier() { return delegate().taxIdentifier(); }
The CLIENT delegate’s implementation of taxIdentifier() is:
public String taxIdentifier() { return employerIdentificationNumber(); }
The PERSON delegate’s implementation is:
public String taxIdentifier() { return socialSecurityNumber(); }
Now imagine something much more complicated such as “exportAllContactInfo” where “Client” needs to iterate over all the employees parse their contact info, flag which ones may perform a specific role and add them all individually to to a single .vcf file that holds multiple contacts. The Person simply writes writes out their own contact info into the .vcf. Each implementation goes in the delegate and the LegalEntity doesn’t know anything about what it takes to put each one together. It’s totally encapsulated in the delegate.
You can enforce what actions a delegate must be able to perform by creating Interfaces that both the LegalEntity and Delegate implement. The LegalEnity’s action() implementation will simply be to call delegate().action()
The biggest drawback to this architecture is the level of abstraction is much higher and therefore can be more complicated to get setup, but it is soooo much more flexible and much more future-proof.
The art of software architecture is knowing when to stop adding levels of abstraction. I think this level of abstraction is always preferable to Inheritance.
Now, back to Address (finally)
You are left with: LegalEntity =>> Address
Easy, no?
(you can model the back pointing relationship if you need a delete rule other than “nullify” when you delete an Address.
Now for some un-asked-for advice! :-)
Do NOT normalize Address! It does not matter if the same address is both billing and shipping. Put it in there twice - even if UI makes it look like it is just one.
This avoids the problem of someone wanting to change only their shipping address but because that one record was both, they end up editing their Billing address too. The UI design needed to deal with one Address with multiple “types" is much more complicated than the UI design needed to manage multiple identical ones.
Dave
On Nov 13, 2013, at 11:37 PM, Ray Kiddy < email@hidden> wrote: On Sep 16, 2013, at 9:51 AM, Joel M. Benisch < email@hidden> wrote: Markus:
As per the private email I sent you over the weekend, which you can most certainly send to the list if you like, I believe that you are confusing things that occur in nature (Organizations, People and Addresses) with the "Roles" that they play in your (or any) environment and implementation.
Have an Entity Object/Table that can contain two types of objects, People and Organizations. A variable in the object will tell you which type "this" object happens to be.
Have an object/table that defines the role that any Entity is "playing" in any given situation. You can therefore have in infinite number of Role Types.
Than have an "EntityAggregate" object/table if you need it. This would be used to relate multiple Entities together into any type of group you may need. Include an AggregateType variable and you can have an infinite number of aggregate types. This allows you to handle Departments, Offices, Spouses, Families or any other type of combination of people you may need. It also allows you to aggregate organizations should you need to do that, like all Vendors of a given type, or all Clients that are serviced by a given employee, or whatever.
The entire bit above can be summarized as "use single-table inheritance". Just FYI. Different sub-entities, even if in the same table, can have different attributes, and it is simple if the attributes are not mandatory. Then you have an Address Object/Table. Addresses can then be associated with any member of the Entity Table, or any number of members of the Entity Table, and you're all set. When an employee or Vendor or Client moves, you don't delete or change the existing (now old/obsolete) address from the table, you add the new one and flag it as "current" if you want. This way, old data will still display and associate to the correct old address that was valid at the time the invoice, or purchase order, or whatever was processed. It also allows you to use the "old" address on another Entity when some other Client or Vendor happens to rent the same space that had previously been occupied by the first one.
I tend to add a deletedDate attribute here. Then, adding a "and the deletedDate is null" qualifier whenever I fetch objects ensures I only see the current ones. We work in the Insurance Industry. This approach has stood the test of time (three decades) quite well. For instance, a person can be a Client, and also a spouse of another Client, and also the Parent of another Client, and therefor a member of a Family Aggregate. That same person can be a Driver on an Auto Policy, an Insured on various policies, an officer of a Client that is an Organization Entity, etc. These are all Roles that this Person Entity is playing.
Wow. Why can't my insurance company do this? My insurer has an idea that my wife is primary on the account and they can't figure out how I relate there. We kept separate last names. What were we thinking. :-)
The person appears once in the Entity Table, but can be used for an unlimited number of Roles.
Just remember, entity inheritance can be your friend, especially if done right.
- ray
Hope this helps, Joel On Sep 16, 2013, at 8:59 AM, Markus Ruggiero wrote: On 15.09.2013, at 06:28, Theodore Petrosky < email@hidden> wrote: Except Clients tend to be businesses with EINs instead of SSNs. So there really are Clients. But sometimes in accounting an employee is a vendor because you need to draw a check outside of the normal employee employer relationship.
I am trying to normalize this structure. Maybe I shouldn't. I would love to hear other people's solutions. but to reiterate, Clients need addresses, People need addresses. if I create a table Address, I could relate it back to Client, and relate it to Person.
So maybe I should change the name to:
Business Person
Person will have two booleans 'isEmployee', and 'isClient', with a SSN Business will have two booleans 'isClient', and 'isVendor' with an EIN
both will have a to-many to Address and each address will have a type (i guess a business address will not be a 'love-nest').
I just never created an Entity that related back to two other Entities. So does that mean
Business <=>> Addresses Person <=>> Addresses
and because of the structure, the relations have to be optional. although an address will always be related to either a Business or a Person.
Or how about an Entity Address and a subclass PersonAddress and another subclass BusinessAddress?
Opinions?
I would model this like so:
Entity "LegalEntity" with "Client" extending "LegalEntity" and "Business" extending "LegalEntity". Both, Client and Business share many common attributes like name etc, Both can have individual attributes like SSN for Clients and EIN for Businesses. Now the addresses: How to model these depends on the answer to the following question: Can the same address be used for different purposes? If no: Create an entity "Address" and have one attribute called "addressType" or some such. AddressType is one out of "home", "work", "love nest" etc. and model "LegalEntity" <-->> "Address" if yes: Create an entity "Address" without a type specifier. Create an intermediate entity like "LegalEntityAddress" with an attribute to specify the type. Model the following relationships: "LegalEntity" <-->> "LegalEntityAddress" <<-> "Address"
Hope this helps. Have fun ---markus---
On Sep 14, 2013, at 10:29 PM, Ramsey Gurley < email@hidden> wrote: Personally, I would look more closely at your person class. Is a client actually a person too? It sounds like it. If so, I would not have a client entity. I would simply make a person entity and assign each person one or more roles. A person might have a client role, a vendor role, and a customer role. Then you simply have a relationship between person and address.
|