views:

154

answers:

2

Apologies if this was already asked but, I have had a look and can't find anything. I am trying to work out the best way to model the following in C#. I have sketched out a few idea but none of them feel right.

I have created an abstract 'Person' class. My application will have Clients and Employees. Obviously, A Client is a Person An Employee is a Person

  • An Employee does not have to be a client.
  • A Client can become an Employee even if they were not initially set up as one.
  • An Employee can become a client
  • An Person can stop being an Employee but remain a Client
  • A Person can stop being a Client but remain an Employee

Ultimately, I will want to map this using Fluent NHibernate. I keep thinking that this should be easy and I just not thinking straight but is there a pattern that I can use that would solve this problem.

Thanks.

+10  A: 

Your problem is your first premise: a Client is not a Person (neither is an Employee). As you've correctly surmised a person can be one, both or neither. So it's not an "is-a" (inheritance) relationship you want here, it's a "has-a" (composition) association.

We haven't been helped in this regard because what you're describing is a typical example that we are taught when we learn OO programming in college, from reading books, etc and it's not a good model.

A Person has zero or more Roles. A Role could be a Customer, Supplier, Employee, Manager or whatever.

If you follow that model through you'll end up with something far more flexible (and accurate).

What I'm describing here is extremely common in CRM systems and tends to be referred to as a Party system. The general idea is:

  • Parties are the key entity for a person or group of people;
  • Partieis have two (or more) subtypes: Person and Organization are common;
  • A Party has zero or more Roles;
  • Sometimes Parties relate to each other but more typically Roles relate to each other.

Example:

  • Joe Smith is a Person, being a subtype of Party;
  • Acme Corp is an Organization, being a subtype of Party;
  • Joe Smith has a role of Employee;
  • Acme Corp has a role of Employer;
  • There is a Role Employment Relationship (a type of Role Relationship) between Joe the Employee and Acme the Employer.

There are many variations on this theme.

cletus
Aw, I see. That makes sense. I knew that I wasn't thinking about it correctly. I'll have a go at modelling that. Thanks Cletus...
Skittles
+1 Good catch about it not being a good model to teach ("has-a", "is-a" is somewhat misleading at times). GoF: "Prefer composition over inheritance". Another way to look at it is if inheritance doesn't make any sense or breaks the model in some way you go for composition instead. :)
Spoike
"Another way to look at it is if inheritance doesn't make any sense or breaks the model in some way you go for composition instead"Have to say Spoike that thinking about it like this really helps..
Skittles
A: 

Hi Cletus, thanks for your response it really helped get things clear in my head. I tried to model my requirements based on your advice, so here is my first pass at the model.

I am putting it up here for 2 reason;

  1. I'm sure if I asked the question, others will have the same question so this may help or be a starting point for them.
  2. I am open to feedback and any advice on how maybe I could model this better to ensure that it is both 'flexible' and 'accurate'

    public class Parties {
        Person Person {get; set;}
        Organization Organisation {get; set;}
        public Parties(Person person, Organization organisation) {
            Person = person;
            Organisation = organisation;
        }
    }
    
    
    public interface Person {}
    public interface Organization {}
    
    
    public class Business : Organization {}
    
    
    public class Contact: Person {
        public string FirstName{get; set;}
        public string LastName {get; set;}
        List<Role>roles = new List<Role>();
            public Contact() {}
            public Contact(Clients client)
                : this() {
                roles.Add(client); 
            }
            public Contact(Employees employee)
                : this() {
                roles.Add(employee); 
            }
        }
    
    
    public interface Role {}
    
    
    public interface Clients: Role{}
    public class BronzeClient: Clients{
        public DateTime lastClass {get; set;}
    }
    public class SilverClient : Clients {
        public DateTime lastClass {get; set;}
    }
    public class GoldClient : Clients {
        public DateTime lastClass {get; set;}
    }
    
    
    public interface Employees : Role {}
    public class Employee: Employees{
        public string EmployeeID{ get; set;}
    }
    public class SeniorManager : Employees {
        public string EmployeeID {get; set;}
    }
    
Skittles