Java 使用访问者模式和界面之间有什么区别?
将访问者设计模式应用于代码与以下方法之间的区别是什么:Java 使用访问者模式和界面之间有什么区别?,java,design-patterns,coding-style,visitor,Java,Design Patterns,Coding Style,Visitor,将访问者设计模式应用于代码与以下方法之间的区别是什么: interface Dointerface { public void perform(Object o); } public class T { private Dointerface d; private String s; public String getS() { return s; } public T(String s) {
interface Dointerface {
public void perform(Object o);
}
public class T {
private Dointerface d;
private String s;
public String getS() {
return s;
}
public T(String s) {
this.s = s;
}
public void setInterface(Dointerface d) {
this.d = d;
}
public void perform() {
d.perform(this);
}
public static void main(String[] args) {
T t = new T("Geonline");
t.setInterface(new Dointerface() {
public void perform(Object o) {
T a = (T)o;
System.out.println(a.getS());
}
});
t.perform();
}
}
我假设通过使用接口,我们并没有真正地分离算法。我看到的唯一显而易见的事情是,通过存储接口,您可以创建它,因此您必须执行两个操作,而不是一个操作来调用它。我认为,如果您在设置界面后重复执行相同的操作,这可能是有意义的,但我认为您可以坚持使用标准访问者并完成相同的任务。这有很大的不同 访问者模式使用接口,但其目的是能够对一个或多个类(实现接口的类)执行操作,而无需更改类。因此,实现实际上是“访问”类,并在不修改类的情况下执行其操作 接口是一个基本概念,用于为可能不同的类组提供公共API。接口的典型测试是,共享接口的类至少在一个方面(is-like-a)是相似的,在这些情况下可以这样处理 有两件事:
- 在您的示例中,需要两种方法。
和perfom
。对于访问者模式,您只需要一种方法,setInterface
,通常称为perfom
李>accept
- 如果需要多个“执行者”,则必须通过
方法为每个“执行者”设置执行者。这使得不可能使类保持不变setInterface
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)
// ...
}
@Override
public void accept(FileSystemVisitor v) {
v.visitFile(this);
}
因为它使用对象,所以它将允许具有任何类型的调用方,这些调用方可以创建只在运行时出现的错误。访问者通过为数据结构中的每种类型创建一个“visitType”函数来解决这个问题。然后,数据结构中的类负责知道要调用访问者上的哪个函数。映射由每个数据结构的类执行,这些类实现一个accept函数,然后调用Visitor类。如果访问者上不存在该类型的函数,则会出现编译错误。accept方法如下所示:
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)
// ...
}
@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);
}
}
公共类访问者示例{
//
公共抽象类FileSystemItem{
公共抽象字符串getName();
公共抽象int getSize();
公开摘要作废接受(FileSystemV);
}
//
公共抽象类FileSystemContainer扩展了FileSystemEmItem{
受保护的java.util.ArrayList _list=new java.util.ArrayList();
//
public void addItem(filesystememitem项)
{
_列表。添加(项目);
}
//
公共文件系统getItem(int i)
{
返回_list.get(i);
}
//
public int getCount(){
返回_list.size();
}
//
公开摘要作废接受(FileSystemV);
公共抽象字符串getName();
公共抽象int getSize();
}
//