альтернатива следующему случаю - PullRequest
0 голосов
/ 19 ноября 2018

Я столкнулся с проблемой, для которой не могу найти легко обслуживаемое и читаемое решение.

Я в основном пишу "главный конечный автомат" У меня есть узел, который получает перечисления от 3 других подчиненных узлов, которые независимо делают свое дело и приходят в определенное состояние и сообщают об этом мастеру

Slave 1 выводит одно из перечислений:

enum slave1 {
A,
B
}

Slave 2 выводит одно из перечислений:

enum slave2 {
1,
2
}

Slave 3 выводит одно из перечислений:

enum slave3 {
a,
b,
c
}

Важно отметить, что я не имею никакого контроля над поведением, структурой и выходами подчиненных узлов

Теперь на основе полученных значений мой мастер-узел имеет следующую логику

val_slave_1 = getSlave1Val();
val_slave_2 = getSlave2Val();
val_slave_3 = getSlave3Val();

switch(val_slave_1):
  case A:
    switch(val_slave_2):
      case 1:
        switch(val_slave_3):
          case a: {do Z}
          case b: {do Y}
          case c: {do X}
      case 2:
        switch(val_slave_3):
          case a: {do W}
          case b: {do V}
          case c: {do U}
  case B:
    switch(val_slave_2):
      case 1:
        switch(val_slave_3):
          case a: {do T}
          case b: {do S}
          case c: {do R}
      case 2:
        switch(val_slave_3):
          case a: {do Q}
          case b: {do P}
          case c: {do O}

Преимущества этого кода -

  1. Учитывая 3 числа, я могу точно узнать, какое поведение ожидать.
  2. Легко отлаживать.
  3. Не нужно поддерживать несколько логических выражений или операторов if.

Проблема с этим кодом в том, что он -

  1. Текущий код представляет собой комбинацию (2,2,3) дел, переставленных вместе, но на самом деле у меня намного больше перечислений (3, 4, 7). Это делает его чрезвычайно трудным для чтения и обслуживания.
  2. Если в будущем один из рабов изменит количество перечислений, скажем, раб 2 добавит еще одно перечисление. Мне нужно будет добавить множество случаев, чтобы сделать эту работу очень сложной для тестирования
  3. Если есть еще один независимый раб (slave 4), который приходит и предоставляет информацию, я просто облажался.

Мой вопрос ко всем вам: есть ли лучший способ сделать это? Я читал много мест, в которых говорилось, что полиморфизм часто является хорошим способом решения операторов switch, но я пытался сделать мой код полиморфным и, похоже, не смог найти решение. Хотя многие люди привели простые примеры транспортных средств и кошек, не похоже, что я могу применить их к своей проблеме.

Еще одно важное замечание: это может быть очевидно, но я все равно напишу это. Неважно, в каком порядке я пишу операторы регистра переключателя. Чтобы сохранить здравый смысл, я выберу запись в порядке от нуля до нуля, чтобы сохранить строки кода (я думаю)

Ближайшая нить, которую я нашел к этой проблеме, -

Существует ли какой-либо шаблон проектирования, позволяющий избежать вложенного корпуса переключателя?

Но есть ли лучший способ сделать это, чем поддерживать словарь перечислений для сопоставления с функцией?

1 Ответ

0 голосов
/ 19 ноября 2018

Поскольку ваши значения перечисления малы, карта из комбинаций перечислений в функции может быть просто массивом. Если у вас есть 3, 4 и 7 значений (то есть 2, 2 и 3 бита соответственно), вы можете использовать один байт для индексации в массиве указателей на функции. Примерно так:

using Handler = void (*)();
std::array<Handler, 128> handlers = { doA, doB, doB, doG, nullptr, ..., doFoo };

int v1 = slave1(); // 0-6
int v2 = slave2(); // 0-3
int v3 = slave3(); // 0-2

int index = (v2 << 5) | (v1 * 3 + v3);
handlers[index]();

Если значения перечисления не являются непрерывными от 0 до n, вам, возможно, придется переназначить их на это.

Возможно, вы захотите придумать умный способ заполнения массива, поскольку пересчет индексов вручную, когда что-то меняется, может занять некоторое время. Один из способов, о котором я могу думать прямо сейчас, - это функция constexpr, которая принимает несколько структур, каждый из которых содержит значения перечисления и указатель на функцию, заполняя массив из них. Структуры будут вычислять индекс, функция будет просто назначать указатели на функции из индексов. Или что-то в этом роде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...