in the reference book "Design Patterns Elements of Reusable Object-Oriented Software" by the gang of four, the intent of the visitor pattern is explained as follow :
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
Another advantage I read about the visitor pattern is that:
ADD A NEW OPERATION WITHOUT HAVING THE SOURCE CODE OF THE CLASSES..
I made a deep search in Google, but I did not find any example showing how to do that. So let's take a simple example :
public interface MyInterface {
public void myMethod();
}
public class MyClassA implements MyInterface {
/* (non-Javadoc)
* @see com.mycomp.tutorials.designpattern.behavorials.MyInterface#myMethodA()
*/
public void myMethod() {
System.out.println("myMethodA implemented in MyClassA");
}
}
public class MyClassB implements MyInterface {
/* (non-Javadoc)
* @see com.mycomp.tutorials.designpattern.behavorials.MyInterface#myMethodA()
*/
public void myMethod() {
System.out.println("myMethod implemented in MyClassB");
}
}
So how would I add a new method myNewMethod()
to this hierarchy of classes without changing them, using the visitor pattern?
Let's say you have a Message class, and 2 subclasses Email and Sms.
You could have many operations on these two classes, like sendToOnePerson()
, sendToSeveralPeople()
. But you probably don't want to have these methods in the Email and Sms class directly, because it tightly couples them to the SMTP/phone system. And you would also like to be able to add other operations in the futre, like forward() or delete(), or whatever. So the first implementation you could use is
public void delete(Message message) {
if (message instanceof Email) {
deleteEmail(Email) message);
}
else if (message instanceof Sms) {
deleteSms((Sms) message);
}
}
But this is ugly: it's not object-oriented, and it will fail if there is a new VoiceMessage subclass appearing.
An alternative is to use the visitor pattern.
public interface MessageVisitor {
void visitEmail(Email email);
void visitSms(Sms sms);
}
public abstract class Message {
public void accept(MessageVisitor visitor);
}
public class Email extends Message {
@Override
public void accept(MessageVisitor visitor) {
visitor.visitEmail(this);
}
}
public class Sms extends Message {
@Override
public void accept(MessageVisitor visitor) {
visitor.visitSms(this);
}
}
This way, to implement send(), all you need is a MessageVisitor implementation that can send an email and send an Sms:
SendMessageVisitor visitor = new SendMessageVisitor();
message.accept(visitor);
And if you introduce a new delete() operation, you don't have to touch to Message classes at all. All you need is a DeleteMessageVisitor:
DeleteMessageVisitor visitor = new DeleteMessageVisitor();
message.accept(visitor);
So, basically, it's a bit like if you added polymorphic methods to the Message classes by not actually modifying the Message classes.