Каковы преимущества и недостатки модели поведения Посетителя?
Я делаю презентацию о шаблоне дизайна посетителя, я понимаю, как он работает и все такое, но мне еще предстоит найти "определенные" преимущества и недостатки, и я не хочу сам додумывать преимущества или недостатки, так как мог установить ложную информацию.
1 ответ
Вот некоторые из моих мыслей о шаблоне посетителя:
Преимущества:
- Основное преимущество: добавить действие ко всем вашим элементам очень просто, так как вам нужно только реализовать интерфейс Visitor. Нет необходимости изменять каждый объект Element, чтобы добавить действие.
- Вы объединяете действия, общие для многих элементов, в один класс посетителя. Только код для этого действия находится в этом классе посетителя. Облегчает чтение кода, если вы хотите знать код для одного действия.
Недостатки:
- Ваш Посетитель может изменить ваши Элементы, так как экземпляр Элемента отправляется Посетителю. Это не рекомендуется, так как это приводит к побочным эффектам. Это можно исправить, сделав ваш объект неизменным.
- Код объектов Element размещен во всех объектах Visitor. Поэтому логика Элемента живет во многих классах. Это затрудняет чтение кода, если вы хотите посмотреть код для одного объекта Element.
- Для каждого действия требуется один новый класс посетителя.
Помимо того, что написал @GammaOmega, еще одним недостатком шаблона посетителя является то, что он инвазивен, потому что для поддержки шаблона посетителя классы, используемые в древовидной структуре, должны предоставлять
accept()
операция. Если вам нужно работать со сторонней древовидной структурой, которая не предоставляет
accept()
операции, то вы не можете использовать шаблон посетителя.
Приведенный ниже псевдокод показывает, как можно выполнить обход дерева, подобный посетителю, без загрязнения классов узлов дерева с помощью
accept()
операция.
void walk(TreeNode * node, NodeProcessor * processorObj)
{
//--------
// This switch statement is used instead of accept() operations
// on nodes in a tree.
//--------
switch (node->getNodeType()) {
case NT_module:
processorObj->processModule((TreeModuleNode*)node);
break;
case NT_interface:
processorObj->processInterface((TreeInterfaceNode*)node);
break;
... // other cases omitted for brevity
}
//--------
// Recurse down the tree
//--------
if (node->isScope()) {
TreeScopeNode * scope = (TreeScopeNode*)(node);
foreach child in scope->getChildren() {
walk(child, processorObj);
}
}
}