Чаще всего существует необходимость в совместном использовании одних и тех же данных между различными объектами / классами.Мне известно о нескольких различных способах сделать это:
- Глобальные переменные: ненавидят большинство и по правильным причинам.
- Синглтоны: это обеспечивает ограниченный контроль над тем, кто может или не можетизмените данные, по крайней мере, для проблемы, описанной ниже.
- Внедрение зависимостей: та же проблема, что и для синглетов.
Иногда такое совместное использование данных порождает дизайн со слабой инкапсуляцией этого общего ресурса.данные.Две общие ситуации, которые возникают довольно часто, таковы:
Состояния, реализующие интерфейс состояний в автомате состояний, нуждаются в доступе к одному и тому же набору данных.
class SharedData
{
public:
double GetVar() const {return var;}
bool GetFlag() const {return flag;}
void SetVar(double in_var) {var = in_var;}
void SetFlag(bool in_flag) {flag = in_flag;}
private:
double var;
bool flag;
};
class StateIface
{
public:
virtual void Run(SharedData* in_shared_data) = 0;
};
class ConcreteStateA : public StateIface
{
virtual void Run(SharedData* in_shared_data) final;
};
class ConcreteStateB : public StateIface
{
virtual void Run(SharedData* in_shared_data) final;
};
Здесь конкретные реализациинапример, ConcreteStateA
потребуется доступ к SharedData
, например, чтобы получить / установить определенные данные, возможно, использовать эту информацию для принятия решения о переходе состояния и т. д. Как и в примере выше, мы могли бы объявить SharedData
как класс и предоставить средства доступа/ мутаторов.Или мы могли бы просто объявить SharedData
как структуру.Однако в обоих случаях конкретные реализации смогут изменять любой параметр в пределах SharedData
.Например, предположим, что ConcreteStateA
не имеет ничего общего с flag
и, следовательно, не должно быть в состоянии изменить его.Однако с данным интерфейсом мы не можем контролировать это поведение.И ConcreteStateA
, и ConcreteStateB
имеют доступ ко всем данным и могут получить / установить любой параметр.Есть ли лучший дизайн / решение для этой проблемы?Тот, который предлагает больше защиты для общих данных.Или можем ли мы каким-то образом применить ограничение, согласно которому определенный ConcreteState
может изменять только определенные параметры SharedData
, в то же время реализуя общий StateInterface
?
Подпрограммам гигантского алгоритма, реализующего интерфейс подпрограммы, необходим доступ к тому же набору данных.
class SubroutineInterface
{
public:
virutal void DoSubroutine(SharedData* in_shared_data) = 0;
}
class ConcreteSubroutine : public SubroutineInterface
{
public:
virutal void DoSubroutine(SharedData* in_shared_data) final;
};
Те же вопросы, что и в примере конечного автомата ...