Пытаюсь применить State pattern, но мне также нужно, чтобы из ConcreteStateA и ConcreteStateB я мог вызывать методы объекта Context, причём нужно сделать так, чтобы эти методы можно было вызывать только из наследников State, т.е. просто сделать эти методы public нельзя.
Получается, если я сделаю нужные методы класса Context приватными, то придётся всех наследников класса State записать во friend'ы класса Context. Это неподходящее решение, поскольку я не смогу создавать новые состояния без модификации класса Context.
Для обхода этой проблемы я создал класс Accessor. Класс Accessor — это friend класса Context, по сути класс Accessor предоставляет интерфейс к нужным приватным методам класса Context, при этом объекты состояний имеют ссылку на Accessor, таким образом, могут вызывать нужные приватные методы класса Context. Конструктор класса Accessor приватный, чтобы кто угодно не мог создать его и получить доступ к приватным методам класса Context.
Вот набросал примерный код этого всего:
#include <iostream>
class Accessor;
class State
{
public:
State(Accessor *accessor) : m_accessor(accessor) {}
virtual ~State() {}
virtual void event1() = 0;
virtual void event2() = 0;
protected:
Accessor *accessor() const { return m_accessor; }
private:
Accessor *m_accessor;
};
class ConcreteStateA : public State
{
public:
ConcreteStateA(Accessor *accessor) : State(accessor) {}
virtual void event1() override;
virtual void event2() override;
};
class ConcreteStateB : public State
{
public:
ConcreteStateB(Accessor *accessor) : State(accessor) {}
virtual void event1() override;
virtual void event2() override;
};
class Context
{
public:
Context();
~Context();
void event1() { m_state->event1(); }
void event2() { m_state->event2(); }
private:
Accessor *m_accessor;
State *m_state;
void setState(State *state) { delete m_state; m_state = state; }
void action1();
void action2();
friend class Accessor;
};
class Accessor
{
private:
Accessor(Context *context) : m_context(context) {}
public:
void setState(State *state) { m_context->setState(state); }
void action1() { m_context->action1(); }
void action2() { m_context->action2(); }
private:
Context *m_context;
friend class Context;
};
Context::Context() :
m_accessor(new Accessor(this)),
m_state(new ConcreteStateA(m_accessor))
{}
Context::~Context()
{
delete m_state;
delete m_accessor;
}
void Context::action1()
{
std::cout << "Context::action1()" << std::endl;
}
void Context::action2()
{
std::cout << "Context::action2()" << std::endl;
}
void ConcreteStateA::event1()
{
std::cout << "ConcreteStateA::event1()" << std::endl;
accessor()->action1();
}
void ConcreteStateA::event2()
{
std::cout << "ConcreteStateA::event2()" << std::endl;
accessor()->action2();
accessor()->setState(new ConcreteStateB(accessor()));
}
void ConcreteStateB::event1()
{
std::cout << "ConcreteStateB::event1()" << std::endl;
accessor()->action1();
accessor()->setState(new ConcreteStateA(accessor()));
}
void ConcreteStateB::event2()
{
std::cout << "ConcreteStateB::event2()" << std::endl;
accessor()->action2();
}
int main()
{
Context context;
context.event1();
context.event2();
context.event2();
context.event1();
context.event1();
return 0;
}
Если посмотреть на код, вся суть должна быть понятна. Вопрос такой: насколько хорошо такое решение? Может, есть решение лучше? Может быть, есть какие-то недостатки, которые я пока что не заметил? Может, это вообще какой-то известный антипаттерн? :D