Когда я нахожу концепцию трудной для понимания, я пытаюсь разобрать ее до самого необходимого. Это случилось со мной недавно с шаблоном посетитель итак, вот мой взгляд на это. Конечно, я буду благодарен за любые исправления. Вот так.
Допустим, у нас есть три класса, производных от общего родителя, называемого
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”