Шаблон проектирования C ++ для избавления от if-then-else - PullRequest
2 голосов
/ 17 октября 2010

У меня есть следующий фрагмент кода:

if (book.type == A)  do_something();
else if (book.type == B) do_something_else();
....
else do so_some_default_thing.

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

Каковы преимущества такого шаблона перед использованием оператора switch?

Ответы [ 8 ]

6 голосов
/ 17 октября 2010

Как уже отмечали другие, виртуальная функция, вероятно, должна быть вашим первым выбором.

Если по какой-то причине это не имеет смысла / не подходит для вашего дизайна, другой возможностью будет использованиеstd::map с использованием book.type в качестве ключа и указателя на функцию (или функтор и т. д.) в качестве связанного значения, так что вы просто ищете действие, которое нужно выполнить для определенного типа (что в значительной степени соответствует количеству ОО-языкових эквивалент виртуальных функций, под капотом).

6 голосов
/ 17 октября 2010

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

Я не говорю, что это обязательно лучше, но это вариант.

2 голосов
/ 17 октября 2010

Каждый другой тип книги - это отдельный подкласс родительского класса, и каждый класс реализует метод do_some_action() с тем же интерфейсом.Вы вызываете метод, когда хотите, чтобы действие имело место.

1 голос
/ 17 октября 2010

Эти if-then-else-if конструкции - одна из самых острых моих любимых мозолей.Мне трудно придумать менее творческий выбор дизайна.Но этого достаточно.Относительно того, что с этим можно сделать.

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

Если число возможностей невелико и расширение в будущемвряд ли я могу просто использовать оператор switch.Но я уверен, что вы не дошли до SOF, чтобы услышать что-то скучное.

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

Если действие связано со сложными вызовами методов, я склонен использовать шаблон проектирования «Цепочка ответственности».Я создам список объектов, каждый из которых знает, как обрабатывать действия для конкретного случая.

Вы передаете элемент для обработки первому объекту-обработчику.Если он знает, что делать с элементом, он выполняет действие.Если это не так, он передает элемент следующему обработчику в списке.Это продолжается до тех пор, пока элемент не будет обработан или не попадет в обработчик по умолчанию, который очищает или печатает ошибку или что-то еще.Обслуживание простое - вы добавляете или удаляете объекты-обработчики из списка.

1 голос
/ 17 октября 2010

Да, это называется циклом:

struct BookType {
    char type;
    void *do();
};
BookType[] types = {{A, do_something}, {B, do_something_else}, ...};
for (int i = 0; i < types_length; i++) {
    if (book.type == types[i].type) types[i].do(book);
}

Хотя для лучшего подхода это даже предпочтительнее, если do_something, do_something_else и т. Д. Является методом Book, поэтому:

struct Book {
    virtual void do() = 0;
};
struct A {
    void do() {
        // ... do_something
    }
};
struct B {
    void do() {
        // ... do_something_else
    }
};

так что вам нужно только сделать:

book.do();
0 голосов
/ 17 октября 2010

В качестве альтернативы наличию отдельного класса для каждой книги, рассмотрите возможность иметь map от типов книг до указателей функций.Тогда ваш код будет выглядеть так (извините за псевдокод, C ++ в наши дни не на кончиках моих пальцев):

0 голосов
/ 17 октября 2010

Шаблон разработки стратегии - это то, что вам нужно.

0 голосов
/ 17 октября 2010

Вы можете определить подкласс для каждого типа книг и определить виртуальную функцию do_something.Каждый подкласс A, B и т. Д. Будет иметь свою собственную версию do_something, к которой он обращается, и do_some_default_thing затем просто становится do_something методом в базовом классе.только один возможный подход.Вы должны оценить, действительно ли это облегчает вам задачу ...

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