Паттерн Состояние на C++
Состояние – это поведенческий паттерн, позволяющий динамически изменять поведение объекта при смене его состояния.
Поведения, зависящие от состояния, переезжают в отдельные классы. Первоначальный класс хранит ссылку на один из таких объектов-состояний и делегирует ему работу.
Особенности паттерна на C++
Сложность:
Популярность:
Применимость: Паттерн Состояние часто используют в C++ для превращения в объекты громоздких стейт-машин, построенных на операторах switch
.
Признаки применения паттерна: Методы класса делегируют работу одному вложенному объекту.
Концептуальный пример
Этот пример показывает структуру паттерна Состояние, а именно – из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.cc: Пример структуры паттерна
#include <iostream>
#include <typeinfo>
/**
* Базовый класс Состояния объявляет методы, которые должны реализовать все
* Конкретные Состояния, а также предоставляет обратную ссылку на объект
* Контекст, связанный с Состоянием. Эта обратная ссылка может использоваться
* Состояниями для передачи Контекста другому Состоянию.
*/
class Context;
class State {
/**
* @var Context
*/
protected:
Context *context_;
public:
virtual ~State() {
}
void set_context(Context *context) {
this->context_ = context;
}
virtual void Handle1() = 0;
virtual void Handle2() = 0;
};
/**
* Контекст определяет интерфейс, представляющий интерес для клиентов. Он также
* хранит ссылку на экземпляр подкласса Состояния, который отображает текущее
* состояние Контекста.
*/
class Context {
/**
* @var State Ссылка на текущее состояние Контекста.
*/
private:
State *state_;
public:
Context(State *state) : state_(nullptr) {
this->TransitionTo(state);
}
~Context() {
delete state_;
}
/**
* Контекст позволяет изменять объект Состояния во время выполнения.
*/
void TransitionTo(State *state) {
std::cout << "Context: Transition to " << typeid(*state).name() << ".\n";
if (this->state_ != nullptr)
delete this->state_;
this->state_ = state;
this->state_->set_context(this);
}
/**
* Контекст делегирует часть своего поведения текущему объекту Состояния.
*/
void Request1() {
this->state_->Handle1();
}
void Request2() {
this->state_->Handle2();
}
};
/**
* Конкретные Состояния реализуют различные модели поведения, связанные с
* состоянием Контекста.
*/
class ConcreteStateA : public State {
public:
void Handle1() override;
void Handle2() override {
std::cout << "ConcreteStateA handles request2.\n";
}
};
class ConcreteStateB : public State {
public:
void Handle1() override {
std::cout << "ConcreteStateB handles request1.\n";
}
void Handle2() override {
std::cout << "ConcreteStateB handles request2.\n";
std::cout << "ConcreteStateB wants to change the state of the context.\n";
this->context_->TransitionTo(new ConcreteStateA);
}
};
void ConcreteStateA::Handle1() {
{
std::cout << "ConcreteStateA handles request1.\n";
std::cout << "ConcreteStateA wants to change the state of the context.\n";
this->context_->TransitionTo(new ConcreteStateB);
}
}
/**
* Клиентский код.
*/
void ClientCode() {
Context *context = new Context(new ConcreteStateA);
context->Request1();
context->Request2();
delete context;
}
int main() {
ClientCode();
return 0;
}
Output.txt: Результат выполнения
Context: Transition to 14ConcreteStateA.
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to 14ConcreteStateB.
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to 14ConcreteStateA.