Шаблон Visitor используется, когда у вас есть структура данных, состоящая из множества разных классов, и у вас есть несколько алгоритмов, которые требуют разных операций для каждого класса. В вашем примере ваша реализация DoInterface делает только одну операцию с одним типом. Единственное, что вы делаете, это печатаете результат getS (), и поскольку вы приводите o к T, вы можете делать это только с классами типа T.
Если вы хотите применить свой интерфейс к типичному классу стиля посетителя, то ваш класс с вашей функцией DoInterface.perform, скорее всего, в конечном итоге получит большой оператор if if if в этом виде:
public void visit(Object o) {
if (o instanceof File)
visitFile((File)o);
else if (o instanceof Directory)
visitDirectory((Directory)o);
else if (o instanceof X)
// ...
}
Поскольку для этого используется объект, он позволяет вызывающим абонентам любого типа создавать ошибки, которые будут отображаться только во время выполнения. Посетитель справляется с этим, создавая функцию «visitType» для каждого типа в структуре данных. Классы в структуре данных затем отвечают за то, какую функцию посетителю вызывать. Отображение выполняется каждым из классов структуры данных, реализующих функцию accept, которая затем вызывает класс Visitor. Если функция для типа не существует для посетителя, вы получаете ошибку компиляции. Метод accept выглядит следующим образом:
@Override
public void accept(FileSystemVisitor v) {
v.visitFile(this);
}
Отчасти проблема с шаблоном Visitor заключается в том, что для того, чтобы по-настоящему оправдать выборку, требуется довольно много кода. Я думаю, именно поэтому многие люди этого не понимают, так как другой код легко отвлекает. Я создал простой пример файловой системы, который, надеюсь, покажет, как использовать посетителя более четко. Он создает композит с несколькими файлами и каталогами, а затем выполняет две операции над иерархией. На практике вы, вероятно, захотите использовать более двух классов данных и две операции для обоснования этого шаблона, но это только пример.
public class VisitorSample {
//
public abstract class FileSystemItem {
public abstract String getName();
public abstract int getSize();
public abstract void accept(FileSystemVisitor v);
}
//
public abstract class FileSystemItemContainer extends FileSystemItem {
protected java.util.ArrayList<FileSystemItem> _list = new java.util.ArrayList<FileSystemItem>();
//
public void addItem(FileSystemItem item)
{
_list.add(item);
}
//
public FileSystemItem getItem(int i)
{
return _list.get(i);
}
//
public int getCount() {
return _list.size();
}
//
public abstract void accept(FileSystemVisitor v);
public abstract String getName();
public abstract int getSize();
}
//
public class File extends FileSystemItem {
//
public String _name;
public int _size;
//
public File(String name, int size) {
_name = name;
_size = size;
}
//
@Override
public void accept(FileSystemVisitor v) {
v.visitFile(this);
}
//
@Override
public String getName() {
return _name;
}
//
@Override
public int getSize() {
return _size;
}
}
//
public class Directory extends FileSystemItemContainer {
//
private String _name;
//
public Directory(String name) {
_name = name;
}
//
@Override
public void accept(FileSystemVisitor v) {
v.visitDirectory(this);
}
//
@Override
public String getName() {
return _name;
}
//
@Override
public int getSize() {
int size = 0;
for (int i = 0; i < _list.size(); i++)
{
size += _list.get(i).getSize();
}
return size;
}
}
//
public abstract class FileSystemVisitor {
//
public void visitFile(File f) { }
public void visitDirectory(Directory d) { }
//
public void vistChildren(FileSystemItemContainer c) {
for (int i = 0; i < c.getCount(); i++)
{
c.getItem(i).accept(this);
}
}
}
//
public class ListingVisitor extends FileSystemVisitor {
//
private int _indent = 0;
//
@Override
public void visitFile(File f) {
for (int i = 0; i < _indent; i++)
System.out.print(" ");
System.out.print("~");
System.out.print(f.getName());
System.out.print(":");
System.out.println(f.getSize());
}
//
@Override
public void visitDirectory(Directory d) {
for (int i = 0; i < _indent; i++)
System.out.print(" ");
System.out.print("\\");
System.out.print(d.getName());
System.out.println("\\");
//
_indent += 3;
vistChildren(d);
_indent -= 3;
}
}
//
public class XmlVisitor extends FileSystemVisitor {
//
private int _indent = 0;
//
@Override
public void visitFile(File f) {
for (int i = 0; i < _indent; i++)
System.out.print(" ");
System.out.print("<file name=\"");
System.out.print(f.getName());
System.out.print("\" size=\"");
System.out.print(f.getSize());
System.out.println("\" />");
}
//
@Override
public void visitDirectory(Directory d) {
for (int i = 0; i < _indent; i++)
System.out.print(" ");
System.out.print("<directory name=\"");
System.out.print(d.getName());
System.out.print("\" size=\"");
System.out.print(d.getSize());
System.out.println("\">");
//
_indent += 4;
vistChildren(d);
_indent -= 4;
//
for (int i = 0; i < _indent; i++)
System.out.print(" ");
System.out.println("</directory>");
}
}
//
public static void main(String[] args) {
VisitorSample s = new VisitorSample();
//
Directory root = s.new Directory("root");
root.addItem(s.new File("FileA", 163));
root.addItem(s.new File("FileB", 760));
Directory sub = s.new Directory("sub");
root.addItem(sub);
sub.addItem(s.new File("FileC", 401));
sub.addItem(s.new File("FileD", 543));
Directory subB = s.new Directory("subB");
root.addItem(subB);
subB.addItem(s.new File("FileE", 928));
subB.addItem(s.new File("FileF", 238));
//
XmlVisitor xmlVisitor = s.new XmlVisitor();
root.accept(xmlVisitor);
//
ListingVisitor listing = s.new ListingVisitor();
root.accept(listing);
}
}