Шаблон посетителя и свободный синтаксис в стиле LINQ для API обхода дерева
Я подумываю о рефакторинге проекта с открытым исходным кодом Afterthought, чтобы сделать его более интуитивно понятным в использовании. Основная идея заключается в том, что разработчики, создающие поправки в Afterthought, будут вносить изменения в конкретный тип.NET и получат возможность изменять сам тип, а также списки свойств, методов, событий, конструкторов и т. Д. (Дерево). API-интерфейсы, которые я использую для внутреннего использования Метаданные Microsoft CCI, широко используют шаблон посетителей в своих API-интерфейсах, поэтому я применил аналогичный подход в Afterthought:
public override void Amend()
{
// Amend the type here, add properties, add methods, etc.
}
public override void Amend<TProperty>(Property<TProperty> property)
{
// Amend properties here
if (property.Name == "Result")
{
// Modify Result property
}
}
public override void Amend(Method method)
{
// Amend methods here
if (method.Name == "Add")
{
// Modify Add method
method.Implement(TInstance instance, int x, int y) => x + y);
}
}
Тем не менее, я обнаружил, что шаблон посетителя в действительности перераспределяет код, решающий целевую проблему (например, инструментарий библиотеки классов), в серию различных методов, ориентированных на аспекты дерева. Это легко реализовать для разработчика, создающего API, но потребитель должен распространять свой код несколько неестественным образом. Поэтому я задаю вопрос: каковы преимущества использования vistor-шаблона по сравнению с простым представлением дерева в виде списков и использованием подхода в стиле LINQ?
Вот альтернативный синтаксис, который я рассматриваю:
public override void Amend()
{
// Do everything here, possibly calling methods just to organize the code
// Modify Add method
Methods.Named("Add").WithParams<int, int>()
.Implement((instance, x, y) => x + y);
}
Таким образом, в этом случае автор поправки может написать весь код в одном месте (или местах по своему выбору), взаимодействуя со списками, которые предоставляют свободный интерфейс /LINQ API вместо переопределения методов. Очевидно, что этот подход немного менее производительный (больше итераций и т. Д.), Но каковы его недостатки?
1 ответ
Шаблон Visitor поможет вам избежать создания if
или же switch
операторы, которые будут проверять тип посещаемого элемента. Избегание этих заявлений обычно считается хорошей практикой. Если выполняемая вами операция не делает различий между различными возможными типами элементов, которые можно посетить, то да, шаблон посетителя не дает вам никакого преимущества по сравнению с вашим альтернативным подходом по сравнению с любым другим подходом.
Проблема, возможно, заключается в понимании шаблона посетителя: речь идет в основном о реализации двойной диспетчеризации на языках, которые не предлагают эту функцию, или (в случае C#), где использование двойной диспетчеризации приводит к значительным проблемам с производительностью. Это не про обход дерева. Это может даже использоваться для классов, которые не формируют иерархическую структуру. В книге GoF говорится, что алгоритм обхода может быть реализован либо самим посетителем, либо посещаемыми элементами, либо даже клиентом.
Изменить: я снова внимательно прочитал ваш вопрос, я думаю, что ваш подход, скажем, альтернативная реализация шаблона посетителя, где посетитель не класс, а набор лямбда-функций.