Как информация о местоположении должна передаваться в шаблоне посетителя? - PullRequest
2 голосов
/ 10 февраля 2009

Скажи, что у меня есть такой посетитель

class Visitor : IVisitor
{
     void Accept(Visitable v)
     {
         /// other code
         v.AChild.Visit(this);
         v.BChild.Visit(this);
     }
}

Где AChild и BChild могут быть одного и того же типа, но код посещения должен различать их (он должен работать по-другому на AChild, чем BChild). Каков наилучший способ сделать это?

  • установить состояние у посетителя и проверить его при следующем вызове
  • передать разных посетителей каждому ребенку
  • другой

Извините, я сделал это задом наперед в первый раз (текущий Accept был Visit). Теперь он соответствует шаблону, как показано в Википедии .

Все методы посещения выглядят так:

void Visit(IVisitor v) { v.Accept(this); }

Ответы [ 3 ]

2 голосов
/ 10 февраля 2009

Вы по-прежнему называете методы в обратном направлении от способа, которым я считаю, что шаблон традиционно используется. Visitable (или Element) обычно имеет метод accept, а Visitor - метод visitX. Я собираюсь использовать традиционную схему именования, чтобы не запутаться: -)

IMO Самый простой способ заставить это работать - использовать несколько методов в интерфейсе посетителя, по одному для каждого типа детей. Не имеет значения, являются ли дети того же типа языка или нет, если они семантически отличаются, они должны обрабатываться разными методами.

Вам также следует избегать загрязнения реализации Visitor сведениями о структуре Visitable. Для этого я бы переместил метод accept в интерфейс Visitable вместо того, чтобы выставлять childA и childB на этом интерфейсе. Затем каждая реализация Visitable может решить, какой метод посетителю вызывать для каждого ребенка. Это сообщает посетителю весь контекст «местоположения» и дает вам хорошее, чистое, отделенное решение.

Вот пример того, о чем я думаю. Я снова поменял имена методов на те, к которым привык.

interface Visitable {
  accept(Visitor v)
}

interface Visitor {
  visitA(Node a)
  visitB(Node b)
}

class Container implements Visitable {
  private Node childA
  private Node childB

  ...
  void accept(Visitor v) {
    v.visitA(childA)
    v.visitB(childB)
  }
}

Теперь у вас есть реализация Visitor, которая имеет 2 различных метода: один для обработки дочерних элементов A и один для обработки дочерних элементов B.

0 голосов
/ 10 февраля 2009

Учитывая следующую дополнительную информацию из ответа в справочный вопрос Оригинального автора:

The visitor object is required to know the structure of the things it visits. That's OK, though. You're supposed to write specialized visit operations for each type of thing the visitor knows how to visit. This allows the visitor to decide how much it really wants to visit, and in what order.

Я бы ответил: создайте специальный класс IVisitor, возможно, с именем ABChildVisitor, который будет иметь метод Visit (), который знает, как пройти AChild и BChild.

0 голосов
/ 10 февраля 2009

Исходя из вашей архитектуры, вам нужно просто позвонить v.Visit(this) и позволить вашей реализации Visitable определить, как работать с AChild и BChild.

Также учтите, что AChild и BChild, вероятно, должны быть частными членами вашего экземпляра Visitable.

...