Taking our view of a person as an actor
as a starting point,
we need first to establish the repertoire of possible behavior.
The Actor Class
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 ami
};
slide: The Actor Class
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.
The Student Actor
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; }
};
slide: The Student Class
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.
The Person is an Actor
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():role [role]; }
private:
int _role;
actor* role[Final+1]; the repertoire
};
slide: The Person is an Actor
A 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.
The Repertoire
person::person() {
for (int i = Person; i <= Final ; i++ ) role[i] = this;
become( Person );
}
slide: The Repertoire
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.
Changing Roles
void person::become(actor* p) { role[Person] = p; } 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;
};
}
}
}
slide: Changing Roles
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.
Becoming adult
class adult_person : public person {
public:
void talk() { cout << "interesting" << endl; }
};
slide: Becoming adult
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(); empty
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
slide: Becoming one's self
The dynamic role switching pattern
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 in [Hush].