Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
State: changing object behavior
The State pattern produces an object that appears to change
its class, and is useful when you discover that you have conditional code in
most or all functions. Like Proxy, State is created by having a front-end
object that uses a back-end implementation object to fulfill its duties.
However, the State pattern switches from one implementation to another during
the lifetime of the front-end object, in order to produce different behavior
for the same function call(s). It s a way to improve the implementation of your
code when you seem to be doing a lot of testing inside each of your functions
before deciding what to do for that function. For example, the fairy tale of
the frog-prince contains an object (the creature) that behaves differently
depending on what state it s in. You could implement this by testing a bool:
//: C10:KissingPrincess.cpp
#include <iostream>
using namespace std;
class Creature {
bool isFrog;
public:
Creature() : isFrog(true) {}
void greet() {
if(isFrog)
cout << "Ribbet!" << endl;
else
cout << "Darling!"
<< endl;
}
void kiss() { isFrog = false; }
};
int main() {
Creature creature;
creature.greet();
creature.kiss();
creature.greet();
} ///:~
However, the greet( ) function, and any other
functions that must test isFrog before they perform their operations,
end up with awkward code, especially if you find yourself adding additional
states to the system. By delegating the operations to a State object that can
be changed, this code is simplified.
//: C10:KissingPrincess2.cpp
// The State pattern.
#include <iostream>
#include <string>
using namespace std;
class Creature {
class State {
public:
virtual string response() = 0;
};
class Frog : public State {
public:
string response() { return "Ribbet!"; }
};
class Prince : public State {
public:
string response() { return "Darling!"; }
};
State* state;
public:
Creature() : state(new Frog()) {}
void greet() {
cout << state->response() << endl;
}
void kiss() {
delete state;
state = new Prince();
}
};
int main() {
Creature creature;
creature.greet();
creature.kiss();
creature.greet();
} ///:~
It is not necessary to make the implementing classes nested
or private, but if you can it creates cleaner code.
Note that changes to the State classes are automatically
propagated throughout your code, rather than requiring an edit across the
classes in order to effect changes.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |