El patrón Estado produce un objeto que parece que cambia su clase, y
le será útil cuando descubra que tiene código condicional en todas o
casi todas sus funciones. Al igual que Proxy, un Estado se crea
teniendo un objeto front-end que usa un objeto back-end de
implementación para completar sus tareas. Sin embargo, el patrón
Estado alterna entre una implementación y otra durante la vida del
objeto front-end, para mostrar un comportamiento distinto ante las
mismas llamadas a función. Es una forma de mejorar la implementación
de su código cuando realiza un montón de pruebas en cada una de sus
funciones antes de decidir qué hacer con esa función. Por ejemplo, el
cuento del príncipe convertido en rana contiene un objeto (la
criatura) que se comporta de modo distinto dependiendo del estado en
el que se encuentre. Podría implementar esto comprobando
un 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(); } ///:~
Listado 9.15. C10/KissingPrincess.cpp
Sin embargo, la función greet(), y cualquier otra función que tenga que comprobar isFrog antes de realizar sus operaciones, acaban con código poco elegante, especialmente cuando haya que añadir estados adicionales al sistema. Delegando las operaciones a un objeto Estado que puede cambiarse, el código se simplifica.
//: 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(); } ///:~
Listado 9.16. C10/KissingPrincess2.cpp
No es necesario hacer las clases FIXME: implementadoras anidadas ni privadas, pero si lo hace, el código será más limpio.
Note que los cambios en las clases Estado se propagan automáticamente por todo su código, en lugar de requerir una edición de las clases para efectuar los cambios.