Предотвращение дублирования кода в процедурно аналогичных функциях, которые имеют разный вывод?

У нас есть какая-то функция foo(g, v, output) которая принимает вершину v ищет некоторый график g для близлежащих вершин и возвращает некоторый вектор информации о пути (шагах), который он предпринял во время этого поиска.

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

Проблема в том, что теперь у нас есть несколько функций (дублирующий код), которые делают что-то вроде этого:

foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo (1)
foo(g, v, output); // (2)
// parse output to get only xs // (3)
}

foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo
foo(g, v, output);
// parse output to get only ys
}

foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo
foo(g, v, output);
// parse output to get only zs
}

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

Проблема в том, что каждое поле имеет другой тип. Кроме этого мы дублируем (1), (2) и большую часть (3).

* На самом деле это на самом деле хуже, потому что нам нужно проверять каждый v так что есть функция, которая вызывает foo_xs, функция, которая вызывает foo_ys и так далее…

2

Решение

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

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

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

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

1

Другие решения

Чтобы решить эту проблему, boost-graph использует visitor концепция. Каждый алгоритм графа использует тип посетителя и вызывает методы посетителя, когда происходят события обхода графа.

Например, посетитель DFS должен определить метод для discover vertex событие и еще один метод для finish vertex событие.

В вашем случае вы бы определили одну реализацию посетителя для каждого из ваших foo_get_XXX() функция, и этот посетитель будет только сообщать полезную информацию.

Рекомендации

2

Примерно так должно работать:

enum Field { xs, ys, zs };
template<Field f>
struct FieldGetter;

template<>
struct FieldGetter<xs> {
typedef int type;
static int get( const BigStructure &o ) { return o.xs; }
}
...

template<Field f, typename T=FieldGetter<f>::type>
std::vector<T> foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo
foo(g, v, output);
// parse output to get only ys
std::vector<T> res;
for( const auto &o : output )
res.emplace_back( FieldGetter<f>::get( o ) );
return res;
}

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector