Типизированный способ предоставления обогащенных зависимостей производным классам в C ++ - PullRequest
1 голос
/ 25 октября 2019

Мой заголовок, вероятно, не велик - я открыт для предложений.

Сейчас у меня есть библиотечный код, который обеспечивает базовую функциональность для класса, имеющего некоторые зависимости. Код выглядит примерно так:

class Fan { /* ... */ };
class PanametricFan : public Fan { /* ... */ };
class DeskFan : public Fan { /* ... */ };

class LogCasing { /* ... */ };
class MalleableLogCasing : public LogCasing { /* ... */ };

struct EncabulatorDependencies
{
  Fan * fan;
  LogCasing * casing;
};

EncabulatorDependencies setupDependencies
  (const std::string & confFile) { /* ... */ }

class Encabulator
{
  public:
    Encabulator(const EncabulatorDependencies & dependencies);

  // ...
};

Теперь в коде пользователя у меня есть что-то вроде этого:

class TurboEncabulator : public Encabulator { /* ... */ }

Теперь пока функционал базового класса в Encabulator может отлично работать с любым типом вентилятора и LogCasing , для TurboEncabulator особенно требуется Panametric Fan и MalleableLogCasing на работу.

Конечно, если файл конфигурации был настроен правильно, то setupDependencies даст мне правильный тип вентилятора и корпуса, который я мог бы просто привести их, например так:

TurboEncabulator::TurboEncabulator(const EncabulatorDependencies & deps)
: Encabulator(deps)
{
  myPanametricFan = dynamic_cast<PanametricFan *>(deps.fan);
  myMalleableCasing = dynamic_cast<MalleableLogCasing *>(deps.casing);

  //..
}

Но я бы хотел сделать что-нибудь более безопасное для типов.

Моя идея состояла в том, чтобы заменить EncabulatorDependencies списком вариантов и получить что-то, что скажет, скажем, "дай мне * 1029"* из этой коллекции "(включая, скажем, указатель на любой производный класс Fan) или" дайте мне PanametricFan * из этой коллекции ". Что-то вроде

Encabulator::Encabulator(const EncabulatorDependencies & deps)
{
  myFan = deps.get<Fan *>();
  myCasing = deps.get<LogCasing *>();
}

в библиотеке и

TurboEncabulator::TurboEncabulator(const EncabulatorDependencies & deps)
{
  myPanametricFan = deps.get<PanametricFan *>();
  myMalleableCasing = deps.get<MalleableLogCasing *>();
}

в коде пользователя.

Тогда метод setupDependencies может просто создать соответствующий объект производного типаи бросить указатель в список зависимостей, Encabulator может иметь Fan *, TurboEncabulator может иметь PanametricFan *, и если файл конфигурации не настроен должным образом, система может выдать нормальное сообщение об ошибке.

Конечно, я могу вспомнить пару «грязных» способов, которыми это может быть достигнуто - EncabulatorDependencies может просто содержать отдельные Fan *, Panametric Fan *, Desk Fan * и т. Д. Указатели и клиентнапример, код может получить тот, который ему нужен, но я надеялся, что существует «правильный» способ сделать это, не требуя дополнительных затрат на обслуживание.

...