Шаблон проектирования для дополнительных функций? - PullRequest
1 голос
/ 21 мая 2009

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

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() { ... }
}

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

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

Ответы [ 6 ]

4 голосов
/ 21 мая 2009

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

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

default:
   doRun(input);

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

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

4 голосов
/ 21 мая 2009

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

1 голос
/ 21 мая 2009

А простое решение:

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 (). Если вам нужно поддерживать более двух уровней (то есть подкласс добавляет еще больше случаев), вам понадобится таблица динамической отправки.

1 голос
/ 21 мая 2009

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

Colin

1 голос
/ 21 мая 2009

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

Почему это так?

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

1 голос
/ 21 мая 2009

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

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

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

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

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

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