Taking our view of a person as an actor as a starting point, we need first to establish the repertoire of possible behavior.
enum Role { Person = 0 , Student, Employer, Final }; class actor { // defines the repertoire public: actor() { } virtual void walk() { if (exists()) self()->walk(); } virtual void talk() { if (exists()) self()->talk(); } virtual void think() { if (exists()) self()->think(); } virtual void act() { if (exists()) self()->act(); } virtual void become(Role) { } // only for a person virtual void become(actor*) { } virtual actor* self() { return this; } // an empty self int exists() { return self() != this; } // who am I };Apart from the repertoire of possible behavior, which consists of the ability to walk, talk, think and act, an actor has the ability to establish its own identity (self) and to check whether it exists as an actor, which is true only if it has become another self. However, an actor is not able to assume a different role or to become another self. We need a person for that!
Next, we may wish to refine the behavior of an actor for certain roles, such as for example the student and employer roles, which are among the many roles a person can play.
class student : public actor { public: void talk() { cout << "OOP" << endl; } void think() { cout << "Z" << endl; } }; class employer : public actor { public: void talk() { cout << "$$" << endl; } void act() { cout << "business" << endl; } };Only a person has the ability to assume a different role or to assume a different identity. Apart from becoming a Student or Employer, a person may for example become an adult_person and in that capacity again assume a variety of roles.
class person : public actor { public: person(); // to create a person void become(Role r); // to become a ... void become(actor* p); // change identity int exists() { return role[Person] != this; } actor* self() { return exists()?role[Person]->self():roleA person may check whether he exists as a Person, that is whether the Person role differs from the person's own identity. A person's self may be characterized as the actor belonging to the role the person is playing, taking a possible change of identity into account. When a person is created, his repertoire is still empy.[ role] ; } private: int _role; actor* role[Final+1]; // the repertoire };
person::person() { for (int i=Person; i <= Final; i++) role[i] = this; become(Person); }Only when a person changes identity by becoming a different actor (or person) or by assuming one of his (fixed) roles, he is capable of displaying actual behavior.
void person::become(actor* p) { role[Person] = p; }Assuming or 'becoming' a role results in creating a role instance if none exists and setting the _role instance variable to that particular role. When a person's identity has been changed, assuming a role takes effect for the actor that replaced the person's original identity. (However, only a person can change roles!) The ability to become an actor allows us to model the various phases of a person's lifetime by different classes, as illustrated by the adult_person class.permanent
void person::become(Role r) { require( Person <= r && r <= Final ); if (exists()) self()->become(r); else { _role = r; if ( role[ role] == this ) { switch (_role) { case Person: break;nothing changes
case Student: role[ role] = new student; break; case Employer: role[ role] = new employer; break; case Final: role[ role] = new actor; break; }; } } }
class adult_person: public person { public: void talk() { cout << "interesting" << endl; } };In the example code below we have a person talking while assuming different roles. Note that the person's identity may be restored by letting the person become its original self.
person p; p.talk();The dynamic role switching idiom can be used in any situation where we wish to change the functionality of an object dynamically. It may for example be used to incorporate a variety of tools in a drawing editor, as illustrated inempty
p.become(Student); p.talk();OOP
p.become(Employer); p.talk();$$
p.become(new adult_person); p.talk();interesting
p.become(Student); p.talk();OOP (new student)
p.become(&p); p.talk();$$ (old role)
p.become(Person); // initial state