Вопрос

У меня есть базовый класс, от которого наследуются производные подклассы, он несет в себе базовые функции, которые должны быть одинаковыми для всех производных классов:

class Basic {
public:
    Run() {
        int input = something->getsomething();
        switch(input)
        {
            /* Basic functionality */
            case 1:
                doA();
                break;
            case 2:
                doB();
                break;
            case 5:
                Foo();
                break;
        }
    }
};

Теперь, основываясь на производном классе, я хочу "добавить" больше операторов case к коммутатору.Какие у меня здесь есть варианты?Я могу объявлять виртуальные функции и определять их только в производных классах, которые собираются их использовать:

class Basic {
protected:
    virtual void DoSomethingElse();
public:
    Run() {
        int input = something->getsomething();
        switch(input)
        {
            /* Basic functionality */
            ...

            case 6:
                DoSomethingElse();
        }
    }
};


class Derived : public Basic {
protected:
    void DoSomethingElse() { ... }
}

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

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

Это было полезно?

Решение

Возможно, вам будет полезно почитать о Схема цепочки ответственности и переосмыслите свое решение таким образом.

Также вы можете объявить 'doRun' как защищенный метод и вызвать его в базовом варианте по умолчанию.

default:
   doRun(input);

И определите doRun в производных классах.

Это так называемый Шаблон Метода шаблон

Другие советы

Я думаю, что шаблон, который вам нужен, это Цепочка ответственности или, может быть СТРАТЕГИИ в сочетании с динамической таблицей вызовов...

Обычный способ справиться с этим - использовать фабрику.В общих чертах:

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

Теперь о дополнительных бонусных баллах:

  • создайте схему, которая повторно регистрирует классы на фабрике - вам нужно будет указать входные данные и тип класса для работы с ними

Теперь, когда возникает необходимость в новых входных данных, вы просто создаете новый класс и регистрируете его на заводе.Необходимость в операторе switch отпадает.

Если ваши значения селектора представляют собой всего лишь небольшие целые числа, я бы заменил оператор case таблицей подстановки.(Каждое действие в этом случае должно быть закодировано как функция, чтобы вы могли поместить указатели на функции в таблицу).Тогда унаследованные классы могут просто добавлять записи в таблицу.(Я предполагаю, что таблица должна быть свойством экземпляра, она не может быть статичной).

Колин

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

Почему это должно быть правдой?

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

А simple solution:

class Basic {
  public:
    void Run() {
      const int input = ...
      if (!(BaseProcess(input) || Process(input))) ...
    }

    vitual bool Process(int input) { return false; }

    bool BaseProcess(int input) {
      switch(input) {
    ...
        default: return false;
      }
      return true;
    }
...

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top