Design pattern visitor with java reflection
Written by Mottola Michele - Italy - Reggio Emilia   
Saturday, 11 April 2015 09:26
Last Updated on Saturday, 11 April 2015 09:34
AddThis Social Bookmark Button

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  

 
#25 Elbert 2021-11-13 21:52
May I simply just saay wuat a relief to discover an individual who actuually understands what they're discussing on the web.
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)
 
 
#24 get more leads 2021-09-17 18:52
I would like to thnkx for the efforts you have put in writing this
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.
 
 
#23 ten tips 2021-09-17 13:11
Woah! I'm really digging the template/theme of this blog.
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!
 
 
#22 natural garden pest 2021-09-16 21:34
I like this website very much so much fantastic information.
 
 
#21 خرید بک لینک دائمی 2021-08-19 03:06
Greetings from Colorado! I'm bored to tears at work so I decided to
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!
 
 
#20 خرید بک لینک دائمی 2021-08-18 20:54
Great information. Lucky me I recently found
your website by accident (stumbleupon). I've bookmarked it for later!
 
 
#19 بک لینک انبوه 2021-08-18 18:09
Currently it appears like Drupal is the best blogging platform out there right now.
(from what I've read) Is that what you are using on your blog?
 
 
#18 Nhà cái w88 2021-08-13 04:27
Amazing! This blog looks just like my old one! It's
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/
 
 
#17 đăng ký 188bet 2021-08-12 17:20
I'm really impressed with your writing skills as smartly as with the format in your weblog.
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/
 
 
#16 genesis pro 2021-08-12 10:17
You are a very bright person!
 

You have no rights to post comments
You have to register to add comments