In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly shows you "how to use Reflection in Java to achieve Visitor pattern", the content is easy to understand, clear, hope to help you solve your doubts, the following let the editor lead you to study and learn "how to use Reflection in Java to achieve Visitor pattern" this article.
Collection is widely used in object-oriented programming, but it often raises some questions about code. For example, "if there are different objects in a collection, how do you operate on it?"
One way is to iterate over each element in the collection and then perform the corresponding operation on each element based on the class in which it is located. This can be difficult, especially if you don't know what types of objects are in the collection. For example, suppose you want to print elements in a collection, you can write a method like this (method):
Public void messyPrintCollection (Collection collection) {
Iterator iterator = collection.iterator ()
While (iterator.hasNext ())
System.out.println (iterator.next () .toString ())
}
It looks simple enough. It just calls the object.toString () method and prints out the object, right? But what if there is a set of hash tables? Things start to get complicated. You must check the type of object returned from the collection:
Public void messyPrintCollection (Collection collection) {
Iterator iterator = collection.iterator ()
While (iterator.hasNext ()) {
Object o = iterator.next ()
If (o instanceof Collection)
MessyPrintCollection ((Collection) o)
Else
System.out.println (o.toString ())
}
}
Yes, the problem of nested collections has been solved, but it requires the object to return String. What if there are other objects that do not return String? What if you want to add quotation marks before and after the String object and f after the Float? The code is still getting more and more complex:
Public void messyPrintCollection (Collection collection) {
Iterator iterator = collection.iterator ()
While (iterator.hasNext ()) {
Object o = iterator.next ()
If (o instanceof Collection)
MessyPrintCollection ((Collection) o)
Else if (o instanceof String)
System.out.println ("'" + o.toString () + "'")
Else if (o instanceof Float)
System.out.println (o.toString () + "f")
Else
System.out.println (o.toString ())
}
}
As you can see, the complexity of things will increase dramatically. Of course you don't want a piece of code full of if-else statements! How to avoid it? Visitor mode can help you.
To implement the Visitor pattern, you need to establish a Visitor interface for visitors and a Visitable interface for the accessed collection. Then, let the concrete class implement the Visitor and Visitable interfaces. The two interfaces are as follows:
Public interface Visitor
{
Public void visitCollection (Collection collection)
Public void visitString (String string)
Public void visitFloat (Float float)
}
Public interface Visitable
{
Public void accept (Visitor visitor)
}
For a specific String, it might be like this:
Public class VisitableString implements Visitable
{
Private String value
Public VisitableString (String string) {
Value = string
}
Public void accept (Visitor visitor) {
Visitor.visitString (this)
}
}
In the accept method, call the correct visitor method on the this type:
Visitor.visitString (this)
In this way, the specific Visitor can be implemented as follows:
Public class PrintVisitor implements Visitor
{
Public void visitCollection (Collection collection) {
Iterator iterator = collection.iterator ()
While (iterator.hasNext ()) {
Object o = iterator.next ()
If (o instanceof Visitable)
((Visitable) o) .accept (this)
}
Public void visitString (String string) {
System.out.println ("'" + string+ "")
}
Public void visitFloat (Float float) {
System.out.println (float.toString () + "f")
}
}
When implementing the VisitableFloat and VisitableCollection classes, they also call the appropriate Visitor method, and the result is the same as the previous messyPrintCollection method that uses if-else, but the technique here is cleaner. In visitCollection (), Visitable.accept (this) is called, and then the call returns to call an appropriate Visitor method. This is called "double dispatch"; that is, Visitor first calls a method in the Visitable class, which is called back into the Visitor class.
Although the if-else statement is eliminated by implementing visitor, a lot of extra code is added. The initial String and Float objects are wrapped in objects that implement the Visitable interface. This is a bit annoying, but generally not a problem, because you can make frequently accessed collections contain only those objects that implement the Visitable interface.
But it seems to be extra work. To make matters worse, what happens when a new Visitable type such as VisitableInteger is added? This is a major flaw in the Visitor model. If you want to add a new Visitable object, you must modify the Visitor interface and implement the corresponding methods in each Visitor implementation class. You can replace the interface with a Visitor abstract base class with a default null operation. That's a lot like the Adapter class in Java GUI. The problem with that method is that it needs to occupy single inheritance; you often want to keep single inheritance for something else, such as inheriting StringWriter. That method has limitations, and it can only successfully access the Visitable object.
Fortunately, Java makes the Visitor schema more flexible, allowing you to add Visitable objects as much as you want. How? The answer is to use Reflection. For example, you can design a ReflectiveVisitor interface that requires only one method:
Public interface ReflectiveVisitor {
Public void visit (Object o)
}
That's it. It's simple. As for Visitable, it's the same as before. I'll talk about it later. Now let's use Reflection to implement PrintVisitor:
Public class PrintVisitor implements ReflectiveVisitor {
Public void visitCollection (Collection collection)
{... Same as above...}
Public void visitString (String string)
{... Same as above...}
Public void visitFloat (Float float)
{... Same as above...}
Public void default (Object o)
{
System.out.println (o.toString ())
}
Public void visit (Object o) {
/ / Class.getName () returns package information as well.
/ / This strips off the package information giving us
/ / just the class name
String methodName = o.getClass () .getName ()
MethodName = "visit" +
MethodName.substring (methodName.lastIndexOf ('.') + 1)
/ / Now we try to invoke the method visit
Try {
/ / Get the method visitFoo (Foo foo)
Method m = getClass () .getMethod (methodName
New Class [] {o.getClass ()})
/ / Try to invoke visitFoo (Foo foo)
M.invoke (this, new Object [] {o})
} catch (NoSuchMethodException e) {
/ / No method, so do the default implementation
Default (o)
}
}
}
You don't need the Visitable wrapper class right now. Just call visit () and the request is distributed to the correct method. The nice thing is that visit () can be distributed as long as you see fit. It is not necessary to use reflection-- it can use other completely different mechanisms.
In the new PrintVisitor, there are methods to write for Collection,String and Float, but then it captures all unhandled types in the catch statement. You need to extend the visit () method so that it can handle all the parent classes as well. First, you have to add a new method, called getMethod (Class c), which returns the method to be called; to find this matching method, look first in all the parent classes of class c, and then in all interfaces of class c.
Protected Method getMethod (Class c) {
Class newc = c
Method m = null
/ / Try the superclasses
While (m = = null & & newc! = Object.class) {
String method = newc.getName ()
Method = "visit" + method.substring (method.lastIndexOf ('.') + 1)
Try {
M = getClass () .getMethod (method, new Class [] {newc})
} catch (NoSuchMethodException e) {
Newc = newc.getSuperclass ()
}
}
/ / Try the interfaces. If necessary, you
/ / can sort them first to define 'visitable' interface wins
/ / in case an object implements more than one.
If (newc = = Object.class) {
Class [] interfaces = c.getInterfaces ()
For (int I = 0; I < interfaces.length; iTunes +) {
String method = interfaces [I] .getName ()
Method = "visit" + method.substring (method.lastIndexOf ('.') + 1)
Try {
M = getClass () .getMethod (method, new Class [] {interfaces [I]})
} catch (NoSuchMethodException e) {}
}
}
If (m = = null) {
Try {
M = thisclass.getMethod ("visitObject", new Class [] {Object.class})
} catch (Exception e) {
/ / Can't happen
}
}
Return m
}
It looks a little complicated, but it's not. In fact, it is just looking for a corresponding method based on the class name passed in. If you can't find it, look for it in the parent class; if you haven't found it yet, look for it in the interface. Finally, take visitObject () as the default.
Note that for those who are familiar with the traditional Visitor schema, I have adopted a traditional naming method for the method name. But as some of you have noticed, it would be more efficient to name all the methods "visit" and then use the parameter type as a distinction. But to do this, you have to change the name of the main visit (Object o) method to something like dispatch (Object o). Otherwise, there is no default method available, and you will have to convert the type to Object when calling visit (Object o) to ensure that visit is called in the correct way.
You can now modify the visit () method to take advantage of getMethod ():
Public void visit (Object object) {
Try {
Method method = getMethod (getClass (), object.getClass ())
Method.invoke (this, new Object [] {object})
} catch (Exception e) {}
}
Now, the visitor object is much more powerful. You can pass in any object, and there is a way to deal with it. Another benefit is that there is a default method, visitObject (Object o), which can capture any unknown object. With a little more effort, you can also write a visitNull () method.
I avoided talking about the Visitable interface above for a reason. Another benefit of the traditional Visitor schema is that it allows Visitable objects to control access to the object structure. For example, suppose you have a TreeNode object that implements Visitable, and you can have an accept () method traverse its left and right nodes:
Public void accept (Visitor visitor) {
Visitor.visitTreeNode (this)
Visitor.visitTreeNode (leftsubtree)
Visitor.visitTreeNode (rightsubtree)
}
In this way, Visitable controlled access can be made with just a few more modifications to the Visitor class:
Public void visit (Object object) throws Exception
{
Method method = getMethod (getClass (), object.getClass ())
Method.invoke (this, new Object [] {object})
If (object instanceof Visitable)
{
CallAccept ((Visitable) object)
}
}
Public void callAccept (Visitable visitable) {
Visitable.accept (this)
}
If you have implemented a Visitable object structure, you can keep the callAccept () method and use Visitable to control access. If you want to access the structure in visitor, simply overwrite the callAccept () method so that it does nothing.
The Visitor pattern can play a powerful role when you want several different visitors to access the same collection of objects. Suppose you already have an interpreter, an infix writer, a suffix writer, a XML writer, and a sql writer, all of which act on the same collection of objects. Then, you can also easily write a prefix writer and a SOAP writer for the same collection of objects. In addition, these writers can work normally with objects they don't know about; of course, you can have them throw exceptions if you want.
The above is all the content of the article "how to use Reflection to implement Visitor pattern in Java". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.