Role ModelingSource: comp.object
Problem: How can the concept of "roles" be modeled using objects?
Eric Hermanson presented the problem:
For instance, let's say you're modeling a hospital and you want objects for "Person", "Nurse", "Patient", "Doctor", etc. Interestingly, a "Person" can be both a "Nurse" and a "Patient" at the same time (a Nurse gets hurt and is admitted to the hospital).
You wouldn't really want Nurse and Patient objects inheriting from "Person" because then you'd have to instantiate two different objects (one for Nurse, one for Patient) for the same person [...]. In my opinion, it would be better if that person could adhere to two roles at the same time - one for Nurse and one for Person.
Amit Patel showed a solution:
One thing that I worry about if I see inheritance used to express roles is that roles can change over time. For example, perhaps the Nurse got hit by lightning and became a Patient, or the Doctor decided to retire.
What I came up with was that the Person object should not be related by inheritance to Nurse, Patient, Doctor, etc. Instead, each role should be a separate object that is associated with the person object. The person object would keep a list of roles, and each role would know which person is playing that role.
For example, there would be an Amit object representing me. Since I'm a Student, there would also be a Student object associated with the Amit object. The student object would contain my student ID, my grades, my enrollment history, and so on. If I fall off my bike and go to the hospital, I am now playing the role of student and patient. The Amit object does not change, except that I'd have to create a new Patient object to represent my being a patient -- patient ID, medical history, list of allergies, treatment, etc. When I leave the hospital, the patient object can be destroyed or archived. If I enter medical school, I might be a Nurse for a while, so I'd create a nurse object. If I graduate, the student object would be destroyed or archived, but I would still be a nurse until I stop playing that role.
This approach allows you to play many roles at once, and to enter and leave roles as needed. I can be a student, a teacher, a doctor, a patient, a passenger, and a volunteer all at once. It also allows me to play two roles belonging to the same 'class' -- for example, if I'm a student at two different colleges, I'd want two student objects to record the student IDs and classes I'm taking at each college.
In general these kinds of things are hard to do with multiple inheritance -- you'd need to be able to remove and add superclasses at run-time (aieeeeee!). You'd also need some way of ensuring that there are no clashes between fields (for example, Doctor.ID has the same name as Student.ID). And you'd need a MI system that allows you to inherit from the same class many times (to handle the case where you are a student at many places).
The separate-objects approach makes message sending more complicated, because you have to direct messages to the role objects yourself. [...] On the other hand, MI might not give you what you need to figure out how to send a message like "turn in final exam" -- the method that needs to be called depends on which class the exam is for, so some user handling of messages may be necessary anyway.
[...] I keep thinking there's a design pattern that can deal with it but I haven't seen one yet. :)
Matthias Hoelzl pointed to some relevant patterns:
Extension Object combined with Product Trader [both from PLoPD3].
Extension Object [Also known as Facet]
In fact, this combination of patterns was documented as an independent pattern:
See The Role Object Pattern by Dirk Bäumer, Dirk Riehle, Wolf Siberski, and Martina Wulf.
Martin Fowler, Dealing with Roles
T Reenskaug, Wold Reenskaug and Lehne Reenskaug,