集合对象大多数情况下都是同类对象的聚集,对集合对象的操作也就是对同类对象的操作。但是,如果集合对象中保存的对象不同,该如何对这些不同类型的对象进行操作?通常会根据对象的类型进行判断再进行操作,就容易出现很多if else语句。如果采用访问者模式,就可以很优雅的解决此类问题,访问者可以利用多态对每一种对象进行访问。
Dom4J中的访问者模式:
public interface Visitor {
/**
* <p>
* Visits the given <code>Document</code>
* </p>
*
* @param document
* is the <code>Document</code> node to visit.
*/
void visit(Document document);
/**
* <p>
* Visits the given <code>DocumentType</code>
* </p>
*
* @param documentType
* is the <code>DocumentType</code> node to visit.
*/
void visit(DocumentType documentType);
/**
* <p>
* Visits the given <code>Element</code>
* </p>
*
* @param node
* is the <code>Element</code> node to visit.
*/
void visit(Element node);
/**
* <p>
* Visits the given <code>Attribute</code>
* </p>
*
* @param node
* is the <code>Attribute</code> node to visit.
*/
void visit(Attribute node);
/**
* <p>
* Visits the given <code>CDATA</code>
* </p>
*
* @param node
* is the <code>CDATA</code> node to visit.
*/
void visit(CDATA node);
/**
* <p>
* Visits the given <code>Comment</code>
* </p>
*
* @param node
* is the <code>Comment</code> node to visit.
*/
void visit(Comment node);
/**
* <p>
* Visits the given <code>Entity</code>
* </p>
*
* @param node
* is the <code>Entity</code> node to visit.
*/
void visit(Entity node);
/**
* <p>
* Visits the given <code>Namespace</code>
* </p>
*
* @param namespace
* is the <code>Namespace</code> node to visit.
*/
void visit(Namespace namespace);
/**
* <p>
* Visits the given <code>ProcessingInstruction</code>
* </p>
*
* @param node
* is the <code>ProcessingInstruction</code> node to visit.
*/
void visit(ProcessingInstruction node);
/**
* <p>
* Visits the given <code>Text</code>
* </p>
*
* @param node
* is the <code>Text</code> node to visit.
*/
void visit(Text node);
}
每一种类型都继承自Node,都实现了接受访问者的accept()方法。
public interface Node extends Cloneable {
。。。
/**
* <p>
* <code>accept</code> is the method used in the Visitor Pattern.
* </p>
*
* @param visitor
* is the visitor in the Visitor Pattern
*/
void accept(Visitor visitor);
。。。
}
当我们想要遍历整个Document时,只需要实现一个简单的访问者,并把他传给Document对象(VisitorSupport继承自Visitor),然后我们就能遍历整个xml文档了。
public class VisitorSample {
public void demo(Document doc) {
Visitor visitor = new VisitorSupport() {
public void visit(Element element) {
System.out.println(
"Entity name: " + element.getName() + "text " + element.getText();
);
}
};
doc.accept( visitor );
}
}
具体的Document遍历操作如下:
public abstract class AbstractDocument extends AbstractBranch implements Document {
。。。
/**
* <p>
* <code>accept</code> method is the <code>Visitor Pattern</code>
* method.
* </p>
*
* @param visitor
* <code>Visitor</code> is the visitor.
*/
public void accept(Visitor visitor) {
visitor.visit(this);
DocumentType docType = getDocType();
if (docType != null) {
visitor.visit(docType);
}
// visit content
List content = content();
if (content != null) {
for (Iterator iter = content.iterator(); iter.hasNext();) {
Object object = iter.next();
if (object instanceof String) {
Text text = getDocumentFactory()
.createText((String) object);
visitor.visit(text);
} else {
Node node = (Node) object;
node.accept(visitor);
}
}
}
}
。。。
}
访问者模式更适用于被访问者相对固定,而访问方式易发生变化的情况。