Когда я нахожу концепцию трудной для понимания, я пытаюсь разобрать ее до самого необходимого. Это случилось со мной недавно с шаблоном посетитель итак, вот мой взгляд на это. Конечно, я буду благодарен за любые исправления. Вот так.
Допустим, у нас есть три класса, производных от общего родителя, называемого
abstract class A
{
public String name;
abstract void accept(Visitor v);
}
класс B, содержащий два объекта в качестве компонентов:
class B extends A
{
public A child1;
public A child2;
public B(String name)
{
this.name = name;
}
[@Override](http://twitter.com/Override)
void accept(Visitor v)
{
v.visitB(this);
}
}
класс C, который имеет один компонент:
class C extends A
{
public A child;
public C(String name)
{
this.name = name;
}
[@Override](http://twitter.com/Override)
void accept(Visitor v)
{
v.visitC(this);
}
}
и класс D, у которого нет компонентов
class D extends A
{
public D(String name)
{
this.name = name;
}
[@Override](http://twitter.com/Override)
void accept(Visitor v)
{
v.visitD(this);
}
}
Все три класса предоставляют свойство, имя, которое позволяет нам различать их экземпляры, и метод с именем accept, который позволяет посетителям посещать их. Классам все равно, и им не нужно знать, чем занимаются их посетители. Посетитель – это интерфейс:
interface Visitor
{
public void visitB(B b);
public void visitC(C c);
public void visitD(D d);
}
Для каждого класса, который он посещает, существует свой метод. Давайте попробуем это с реализацией посетителя, которая просто выводит названия объектов, которые он посетил:
class PrintVisitor implements Visitor
{
public void visitB(B b)
{
b.child1.accept(this);
System.out.println(b.name + " visited.");
b.child2.accept(this);
}
public void visitC(C c)
{
System.out.println(c.name + " visited.");
c.child.accept(this);
}
public void visitD(D d)
{
System.out.println(d.name + " visited.");
}
}
Посетитель рекурсивен: он посещает узел дерева, а затем посещает его дочерние элементы. Теперь давайте создадим дерево, составленное из классов B, C и D:
/\*
F
/ \
B G
/ \ \
A D H
/ \ \
C E I
\*/
Существует девять объектов и семь отношений. Сначала создайте объекты:
B f = new B("F");
B b = new B("B");
B d = new B("D");
C g = new C("G");
C h = new C("H");
D a = new D("A");
D c = new D("C");
D e = new D("E");
D i = new D("I");
Далее, отношения:
f.child1 = b;
f.child2 = g;
b.child1 = a;
b.child2 = d;
d.child1 = c;
d.child2 = e;
g.child = h;
h.child = i;
И, наконец, начните посещать свое дерево, посетив его корневой узел:
PrintVisitor v = new PrintVisitor();
f.accept(v);
Результат таков:
A visited. B visited. C visited. D visited. E visited. F visited. G visited. H visited. I visited.
Если вы посмотрите на эту статью , приведенный выше код выполняет обход дерева и то, что называется обход по порядку при этом (). Давайте изменим наш класс посетителей, чтобы выполнить обход предварительного заказа – посетитель сначала отображает имя узла, а затем посещает его дочерние элементы:
class PrintVisitor implements Visitor
{
public void visitB(B b)
{
System.out.println(b.name + " visited.");
b.child1.accept(this);
b.child2.accept(this);
}
public void visitC(C c)
{
System.out.println(c.name + " visited.");
c.child.accept(this);
}
public void visitD(D d)
{
System.out.println(d.name + " visited.");
}
}
Теперь результат таков:
F visited. B visited. A visited. D visited. C visited. E visited. G visited. H visited. I visited.
В обходе после заказа посетитель сначала посещает дочерние узлы и только затем отображает их имя:
class PrintVisitor implements Visitor
{
public void visitB(B b)
{
b.child1.accept(this);
b.child2.accept(this);
System.out.println(b.name + " visited.");
}
public void visitC(C c)
{
c.child.accept(this);
System.out.println(c.name + " visited.");
}
public void visitD(D d)
{
System.out.println(d.name + " visited.");
}
}
Вот результат:
A visited. C visited. E visited. D visited. B visited. I visited. H visited. G visited. F visited.
Помимо статьи в Википедии, на которую я ссылался в начале, есть хорошее описание шаблона посетителей здесь . Короче говоря:
- Посещаемым объектам не нужно знать, что делают их посетители, им просто нужно принять их.
- Должен существовать протокол, позволяющий взаимодействовать посещаемым объектам и посетителям, в нашем случае интерфейс посетителя.
- Посетитель использует отдельные методы (т. е. посещение B, посещения и посещения для посещения каждого класса)
(Вы можете найти код на Github .)
Оригинал: “https://dev.to/vicentemaldonado/visitor-pattern-in-java-3lh1”