И посетитель, и стратегия, и шаблон шаблона охватывают применение алгоритма. Самая большая разница в том, как они вызваны и как они используются на практике. Хотя может показаться, что они используют один и тот же вариант использования, посмотрите на конструкцию объектов, чтобы увидеть разницу.
Шаблон стратегии часто используется, когда у нас нет возможности передавать функции как объект первого класса. Он ожидает очень специфический список аргументов и только этот список аргументов в шаблоне вызовов. Например:
struct MyStrat{
void operator()(const Foo &_input){
_input.up( 2 );
}
};
std::for_each( myFooList.begin(), myFooList.end(), MyStrat() );
, который затем применяется к списку объектов типа «Foo». У нас действительно нет другого способа применить его к любому другому объекту.
Шаблон посетителя, с другой стороны, используется, когда мы хотим применить алгоритм к группе объектов, которые могут не иметь одинаковую подпись или иметь одинаковые функции-члены. Мы говорим шаблон посетителя, потому что он часто используется при обходе дерева или другой коллекции «не связанных» объектов (не связанных в смысле наследования).
struct MyVisitor{
void visit(const Foo &_input){
_input.up( 2 );
}
void visit(const Bar &_input){
_input.raiseUp( 2 );
}
void visit(const Baz &_input){
_input.setUp( 2 );
}
};
Здесь идея в том, что мы хотели бы «поднять» все эти объекты. Все они не имеют одинаковую сигнатуру функции-члена, но все они концептуально связаны. Следовательно, мы можем «посещать» каждый из этих классов, но ожидать, что алгоритм выполнит задачу того же типа.
Используя шаблон посетителя, мы избегаем необходимости заключать каждый класс в шаблон прокси. Следовательно, для N классов мы хотели бы применить этот алгоритм, чтобы нам не нужно создавать N прокси-классов. Нам нужно только добавить N методов в класс посетителя.
Метод шаблона довольно сильно отличается от шаблона посетителя и стратегии. С помощью шаблона вы пытаетесь применить алгоритм того же типа, но на разных подклассах в иерархии. Например:
class Duck{
public:
int count() =0;
void makeNoise(int times) =0;
void quack(){ makeNoise( count() ); }//the template pattern is here
};
class Mallard : public Duck{
public:
int count(){ return 4; }
void makeNoise( cout << "quack" << endl; }
};
class Daffy{
public:
int count(){ return 1; }
void makeNoise( cout << "Why I ought to..." << endl; }
};
Таким образом, результат алгоритма варьируется в пределах иерархии.