Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Тут стоит подчеркнуть, что у паттерна Посетитель есть две независимые стороны
— разнести алгоритм работы с контейнером и алгоритм работы с элементом
Итератор и Посетитель, конечно, ходят рука об руку.
Во-первых, единственный объект тоже является контейнером самого себя с одним тривиальным способом обхода.
Посетитель — это и идея инъекции алгоритма в алгоритм (полиморфизм со стороны посетителя), и идея взаимодействия с невидимыми извне разнотипными объектами (полиморфизм с принимающей стороны).
Педалировать какую-то одну грань и упускать другую — было бы странно.
это и идея инъекции алгоритма в алгоритм (полиморфизм со стороны посетителя), и идея взаимодействия с невидимыми извне разнотипными объектами (полиморфизм с принимающей стороны).
accept?class person_t
{
public:
person_t(const std::string& name, size_t age)
: name_(name), age_(age){}
template<typename Visitor>
void accept(Visitor& v) {v.visit(*this);}
size_t age() const {return age_;}
private:
std::string name_;
size_t age_;
};
struct person_visitor_t
{
person_visitor_t(size_t age_limit) : age_limit_(age_limit){}
bool operator()(const person_t& p) {return visit(p);}
bool visit(const person_t& p) {return p.age() < age_limit_;}
size_t age_limit_;
};
struct person_visitor_t
{
person_visitor_t(size_t age_limit) : age_limit_(age_limit){}
bool operator()(const person_t& p) {return p.age() < age_limit_;}
size_t age_limit_;
};
STL и visitor.dynamic покрывает, наверное, больше 90% случаев, но все же это немного другое, т.к. не используется условие, что сами объекты знают о том, что их может “навестить” некий обработчик. Иногда эта дополнительная гибкость может быть очень полезной.double dispatch толком не нужен.
CallSite<Action, CallSite, Visitor, object>>CSharpArgumentInfo::CreateRuntimeBinder.Binder::InvokeMemberCallSite<Action<CallSite, Visitor,object>>::Invoke class Program
{
static void Main(string[] args)
{
var pl = new List<Person>();
var r = new Random();
for (int i = 0; i < 1000000; i++)
{
pl.Add(r.Next(100) < 50 ? (Person)new Man() : new Woman());
}
var p = new Man {Children = pl.ToArray()};
var v = new Visitor();
var sw = new Stopwatch();
sw.Start();
v.Process(p);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw = new Stopwatch();
sw.Start();
v.Process2(p);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
public abstract class Person
{
public IList<Person> Children { get; set; }
}
public class Man : Person { }
public class Woman : Person { }
public class Visitor
{
public void Process(Person person)
{
foreach (dynamic p in person.Children)
Visit(p);
}
public void Process2(Person person)
{
foreach (var p in person.Children)
{
var m = p as Man;
if (m != null) Visit(m);
else Visit((Woman)p);
}
}
void Visit(Man m) { mc++; }
void Visit(Woman w) { wc++; }
private int mc, wc;
}
template<typename V>
void accept(V& visitor) { visitor.visit(*this); }
Идиомы С++. Static visitor