What is the problem
I have a collection of object of different type and i want add some behaviour without modify existing classes. More specific i want add different behaviour based on object's type.
In our case i have objects of type Ferrari and Maserati and i want modify the property colour of this objects and print some message when i do that (this is the new behaviour). Due to this i want object of Ferrari in red and object of Maserati in blue.
Class diagram
Why use visitor
Without the visitor i could create objects of type ConcreteElement and then modify this classes and recompile, but it it a bad idea. Or i could use if statement, something like: if object is of type Ferrari then do that, if is of type Maserati do that. But every time i add new type of object i need to modify that code.
The visitor avoid the modification of that classes and allow to add different behavioural on each type of object.
How visitor work
Basically it work so: the client loop through all object of the collection of type Element (they are inside the object of type Cars, that is only a wrapper) and, for each it invoke the accept method providing an instance of ConcreteVisitor. That method then invoke the visit method that is a method that provide our new behaviour for that type of ConcreteElement. In our example, that method is responsable to change the colour attribute and to print a message.
It is to note that each ConcreteVisitor is able to define an different algorithm based on the type of Element provided.
Sequence diagram
Why use reflection
In standard version of visitor it's used one visit method for each type of ConcretElement. The drawback of this pattern is the creational dependencies that create this, so when i add new ConcreteElement i must modify the interface of visitor and therefore all ConcreteVisitor. In this version of visitor instead the interface of visitor has only one method that accept an object of type Object. Therefore i don't have creationa dependencies. Now if i add new ConcreteElement i don't need to modify the interface of visitor. The reflection help into identification of the type of object provided and in the invocation of the right visit method. More specific accept method of ConcreteVisitor invoke visit(Object o) method. Here it define invoke() method that call the right visit() method based on the type of object provided.
Java implementation
Visitor.java
package visitor5;
public interface Visitor {
public abstract void visit(Object o);
}
ConcreteVisitor1.java
package visitor5;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ConcreteVisitor1 implements Visitor {
@Override
public void visit(Object o) {
try {
Method m = getClass().getMethod("visit", o.getClass());
m.invoke(this, o);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
noMethod(o);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void visit(Ferrari f){
f.setColour("red");
System.out.println("the colour of object Ferrari is now red");
}
public void noMethod(Object o){
System.out.println("no method");
}
}
ConcreteVisitor2.java
package visitor5;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ConcreteVisitor2 implements Visitor {
@Override
public void visit(Object o) {
try {
Method m = getClass().getMethod("visit", o.getClass());
m.invoke(this, o);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
noMethod(o);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void noMethod(Object o){
System.out.println("no method");
}
public void visit(Maserati m){
m.setColour("blue");
System.out.println("the colour of object Maserati is now blue");
}
public void visit(Ferrari f){
f.setColour("red2");
System.out.println("the colour of object Ferrari is now red2");
}
}
Car.java
package visitor5;
public interface Car {
public abstract void accept(Visitor v);
}
Ferrari.java
package visitor5;
public class Ferrari implements Car {
private String colour;
@Override
public void accept(Visitor v) {
// i must to call visit(Object o) so i need a cast of this
Object o=(Object) this;
v.visit(o);
}
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
public Ferrari(String colour) {
super();
this.colour = colour;
}
}
Maserati.java
package visitor5;
public class Maserati implements Car {
private String colour;
@Override
public void accept(Visitor v) {
// i must to call visit(Object o) so i need a cast of this
Object o=(Object) this;
v.visit(o);
}
public Maserati(String colour) {
super();
this.colour = colour;
}
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
}
Cars.java
package visitor5;
import java.util.ArrayList;
import java.util.List;
public class Cars {
private List<Car> cars= new ArrayList<Car>();
public void attach(Car c){
cars.add(c);
}
public void Accept(Visitor v){
for(Car c:cars){
c.accept(v);
}
}
}
Client.java
package visitor5;
public class Client {
public static void main(String[] args) {
Cars e = new Cars();
e.attach((Car) new Ferrari("green"));
e.attach((Car) new Ferrari("yellow"));
e.attach((Car) new Ferrari("white"));
e.attach((Car) new Maserati("cyan"));
e.attach((Car) new Maserati("black"));
System.out.println("applied ConcreteVisitor1");
ConcreteVisitor1 inc = new ConcreteVisitor1();
e.Accept(inc);
System.out.println("-----------------------");
System.out.println("applied ConcreteVisitor2");
ConcreteVisitor2 inc2 = new ConcreteVisitor2();
e.Accept(inc2);
}
}
Execution
As you can see the object of type ConcreteElement1 is able to handle only object of type Ferrari, therefore il launch an exeption and print a message 'no method' when accept method invoke the visit method and pass it an object of type Maserati.
Moreover you can note that the visit method on object of type Ferrari has implemented in different way in our two ConcreteVisitor. Indeed one set the color to 'red' and the other to 'red2'.
Output
applied ConcreteVisitor1
the colour of object Ferrari is now red
the colour of object Ferrari is now red
the colour of object Ferrari is now red
no method
no method
------------
applied ConcreteVisitor2
the colour of object Ferrari is now red2
the colour of object Ferrari is now red2
the colour of object Ferrari is now red2
the colour of object Maserati is now blue
the colour of object Maserati is now blue
|
Comments
You actually understand how to bring ann isse to light and make iit
important. More and more people ought to check this
out and understand this side oof the story. I waas surprised you're
not morre popular since you surely possess the gift.
My web page :: Runescape staker (Elbert: https://probemas.com/osrs-max-main-rentals)
website. I am hoping the same high-grade website post from you in the upcoming also.
In fact your creative writing abilities has inspired me to get my own site now.
Actually the blogging is spreading its wings rapidly.
Your write up is a great example of it.
It's simple, yet effective. A lot of times it's hard to get that
"perfect balance" between user friendliness and visual appearance.
I must say that you've done a fantastic job with this.
Also, the blog loads very quick for me on Safari. Outstanding
Blog!
check out your blog on my iphone during lunch break.
I enjoy the knowledge you provide here and can't wait to take
a look when I get home. I'm surprised at
how quick your blog loaded on my mobile .. I'm not even using
WIFI, just 3G .. Anyhow, good blog!
your website by accident (stumbleupon). I've bookmarked it for later!
(from what I've read) Is that what you are using on your blog?
on a totally different topic but it has pretty much the same
layout and design. Excellent choice of colors!
Here is my blog; Nhà cái w88: https://w88vao.com/
Is this a paid subject or did you modify it yourself?
Either way keep up the excellent high quality writing, it is rare to peer a nice blog like this one today..
Also visit my blog - đăng
ký 188bet: https://www.188bongda.com/188bet-dang-ky/
RSS