The
visitors
What are the participants of the design pattern "visitor"?
AA
object tree (tree, list ...): A collection of objects, we call them represent elements that are instances of a manageable small set of classes. Let's call these classes element types.
operation
That is to be executed on this object structure by
a
processor traverses the object structure and for each pass element is a call depending on the element type, different method.
The goal of the design pattern "Visitor" is, the operation belonging to separate the code from both the processor and the element types and to encapsulate in a separate object type: the visitor interface.
The visitor interface provides a method for each type of item available. All these methods can be named the same and only differ in the type of their argument. This is only possible in languages such as Java, overloading the Allow methods, but eg not in ABAP (there, the methods must then just be named differently for each element type).
If we choose as the object structure to illustrate the XML DOM would have to offer the visitor class, for example, the following set of methods:
interface Visitor {
public void visit (n ElementNode);}
public void visit (text node n);
public void visit (CommentNode n);
...
accept () on
method, so that is on the way to the appropriate operation of each element
Visitor
s running.
method is a bad disadvantage of the Visitor pattern: we can not use the standard XML DOM in Java, such as the org.w3c.dom package
, but have to boarding any class of the DOM by a self-programmed class to introduce the new method. Since it is a small consolation that this method is at least couched in general terms, so that it uses for various tasks can be. That the object used in the structure of concrete element classes the method accept () must implement is rather a classic case of "intrusion".
yourself too, we must, if we repeat the principle
DomTree
Do not take them seriously and push it to the implementations of each element class always contain the following delegation same code (although that is natural for the design patterns are not required):
ElementNode class implements Node {
...
public void accept (Visitor visitor) {
visitor.visit (this);}
}
Concrete Implementation is only there so that the overcharge mechanism visit by element type, the respective correct
() method of the visitor
binds. If the implementation was lacking, overloading would not work correctly because static in Java binding on overloading, that already takes place at compile time, the compiler can not and does not want to know what concrete object type at run-time visit in fact when you call the
(node)
method is passed.
The processor now tells the passed elements to accept visitors. Let's say, the class
Implement an iterator to traverse its elements. Then, the operation the concrete visitor performed as follows: void process (Visitor visitor, DomTree domTree) for (Node n: domTree) { n.accept (visitor);}
}
accept (Visitor)
method with all elements of the object structure is squeeze. The executed operations are as it were from within, out of the elements of the object structure called. Is this really necessary just to achieve a separation of operations-from the element code? consists Why have an interest in the visitor through the objects ? Sent through Separation of Concerns could also be a much simpler design to achieve, in which the elements can not accept a logic of its foreign
() method
be dirty, but remain so, as they can. To stay in the picture: The visitor design pattern allows visitors to the living room. One can also set up so that you can enter the person does not, but cleared for already at the door! One might call this design pattern. Make In
peddler.
Suppose again for simplicity, our object tree is a DOM tree. Then we can find this object structure as a separate component, a
TreeWalker
TreeWalker
is defined as the DOM tree is traversed. Since the
TreeWalkerleave:
is competent to go through the elements of the object structure, it is a natural decision,
visit calling the
()
method with
TreeWalker
He made the Visitor sends for each pass the element visit () message. A
accept ()
method is not needed then! The
:
import org.w3c.dom .*; import org.w3c.dom.Node; / / The name "Node" is not in Java clearly import static org.w3c.dom.Node .* / / Node constants
class TreeWalker
{public void process ( Node s, Visitor v) {NodeList children =
n.getChildNodes (); int numberOfChildren children.getLength = (); for (int i = 0; process (children.item (i), v);
v.visit} (n);}
} This intuitive design you have all three components are separated clearly. The object structure, the passage of the sub-objects, and finally the visitor when passing through the object structure, the Part objects in turn procured and presented to the visitor for processing. It is therefore for the Node objects that the TreeWalker
and referred to it during his walk through the DOM tree. To the operations of the type of run-time element to the passed to the condition must be used by any type of Reflection: Depending on the type of need in each case different methods are executed. In
org.w3c.dom
, each node has a particular node type that the method getNodeType
()
can be queried. Thus we save ourselves in this case, the use of Java Reflection API to the currently This item class to be determined.
- The node types are small whole numbers. It can be used in the Visitor
- implementation as an index of an array of methods references. Since there are no methods in Java references are recommended anonymous inner classes. The following Visitor are for items the item name and text nodes the text content in the console: class ExampleVisitor implements Visitor {
- private static Visitor [] visitorFor = new Visitor [ 10]; static { visitorFor [ELEMENT_NODE] = new Visitor () {public void visit (Node n) {
- }}; visitorFor [TEXT_NODE] = new Visitor () {public void visit (Node n) {
/ / The following array visitorFor "serves us as a dispatcher
System.out.println ("Item" + ((Element) n) GetTagName ().)
system. out.println ("Text node:" + n.getTextContent ());}
};
/ / etc. for the other node types
/ / limited amount that will not change practically
} public void visit ( Node n) {
/ / dispatching
visitorFor [n.getNodeType ()] visit (s).the sake of completeness here are the Test Class lists with which I have tried the whole design. It is based on a sample document and returns the root element and the visitors instance to the
}}
TreeWalker
class Test { public static void main (String [] args) throws Exception { / / XML document read from a test string
Document testdoc = getDocumentFromString (
"\u0026lt;? xml version = \\" 1.0 \\ "encoding =" utf-8 \\ "?>"+ "\u0026lt;a> b \u0026lt;c> \u0026lt;d/> e \u0026lt;/ c> \u0026lt;/ a> "); / / All objects with the help of TreeWalker visit . TreeWalker new () process ( / / 1.Argument: root node of the XML document testDoc.getDocumentElement () / / 2.Argument: Visitor object ExampleVisitor new ());}
private static Document getDocumentFromString (String doc) throws Exception {
return
javax.xml.parsers.DocumentBuilderFactory.newInstance ()
. newDocumentBuilder ()
. parse (new
org.xml.sax.InputSource (
new java.io.StringReader (doc )));}
}
The test class is for the sample document \u0026lt;a> b \u0026lt;c> \u0026lt;d/> e \u0026lt;/ c> \u0026lt;/ a> the expected result of: text nodes: b
element d
text nodes: e element c element a
we go once listed in [1]
consequences
of the design pattern
visitors
and compare it with the design presented here:
visitors make adding new operations easy.
This is also true: In fact, neither the need nor the types of items TreeWalker be changed when a new Visitor object is developed.
A visitor brings together related operations and separates them of operations which have nothing to do with the task of the visitor. is plainly satisfied here as well. Adding new element classes is hard. For us it is easier than in the Visitor pattern. Our Visitor interface contains so only one method. When adding new item classes, this method is valid because it is defined with the general element interface. The code to be executed for a particular operation must be implemented of course. The dispatch mechanism, however, could easily be formulated so that for unknown element classes simply no action is taken. Class hierarchy Cross visitors. This establishes that the elements visited in the Visitor pattern must not necessarily be derived from a common superclass. That is true. But they must all accept the (Visitor) method mentioned in their public interface. So you do not need a common superclass, but a common interface. This limits the usefulness of a Visitor pattern. For the presented draft, however, there are absolutely no restrictions to the element classes. Also inherit if the DOM element instance, all classes of node, this is not necessary. The common superclass could also be Object
. The existence of a common element interface allows visitors, however, perform their work more effective (because otherwise worked with Reflection
must
).So there is no need to provide visitors with a pass to send
accumulation of state information
. The visitor can while he visits the nodes to collect information in its attributes. This is equally possible.
< numberOfChildren; ++i) {
breaking the encapsulation.
Since the visitor can access only the public components of the item class, it can happen that one is forced to publish internal information of the object to allow the visitor his work. This is a consequence which is in this form for all client-server relationships between objects, regardless of the visitor pattern.
accept (Visitor)
interface with the objects of the object structure. There are simpler and more obvious designs that provide the same as the Visitor pattern.
[1] Gamma, E, Helm, R. Johnson, R., Vlissides J.: Design Patterns .- elements of reusable object-oriented software , Addison-Wesley Germany 1996th
0 comments:
Post a Comment