The Visitor pattern is useful in designing an operation across a heterogeneous collection of objects of a class hierarchy. The Visitor pattern allows the operation to be defined without changing the class of any of the objects in the collection.
To accomplish this, the Visitor pattern suggests defining the operation in a separate class referred to as a visitor class. This separates the operation from the object collection that it operates on. For every new operation to be defined, a new visitor class is created. Since the operation is to be performed across a set of objects, the visitor needs a way of accessing the public members of these objects. This requirement can be addressed by implementing the following two design ideas.
Example
Let us design an application to define operations over a collection of different Order objects. Orders can be of different types. Let us consider three different types of orders as follows:
- Overseas order — Order from countries other than the United States. Additional shipping and handling is charged for this type of order.
- California order — U.S. order with shipping address in California. Additional sales tax is charged on this type of order.
- Non-California order — U.S. order with shipping address not in California. Additional sales tax is not applicable.
Let us say that we would like to add more methods, such as getMinCAOrderAmount, getCAOrderTotal, getMinNonCAOrderAmount, getMax-OverseasOrderAmount, etc., to find out different types of order amounts.
If we are going to add these methods to the Order class, The Order class code needs to be altered for each such new operation. As a result, the class can quickly become cluttered.
As solution we can use Visitor pattern.
- When run, the client OrderManager creates an instance of the OrderVisitor and displays the necessary user interface to allow a user to create different types of orders.
- Every time a user enters the order data and clicks on the CreateOrder button, the client OrderManager,
- Creates an Order object with the input data.
- Invokes the accept(OrderVisitor) method on the Order object bypassing the OrderVisitor object. The Order object internally calls the OrderVisitor visit method by passing itself as an argument. The OrderVisitor retrieves the required order amount, tax and shipping amounts using the public methods defined by different Order classes and adds these amounts, in a cumulative manner, to the order total kept inside the private instance variable orderTotal.
When the GetTotal button is clicked, the client OrderManager invokes the getOrderTotal method of the OrderVisitor. The OrderVisitor simply returns the value stored in the orderTotal instance variable, which is the total value of all orders created.
Defining a new operation on the order object collection
Defining a new operation on the order object collection requires the creation of a new visitor. The new visitor needs to implement the VisitorInterface interface providing implementation for different visit(OrderType) methods to process different types of Order objects.
Adding new Order type to the collection
If a new type of object (a new class) is to be added to the object structure such as a DiscountOrder that implements the Order interface, then a corresponding visit(DiscountOrder) method needs to be added to the VisitorInterface and needs to be implemented by the OrderVisitor class.
public interface VisitorInterface {
public void visit(NonCaliforniaOrder nco);
public void visit(CaliforniaOrder co);
public void visit(OverseasOrder oo);
}
public interface Order {
public void accept(VisitorInterface v);
}
public class CaliforniaOrder implements Order {
private double orderAmount;
private double additionalTax;
public CaliforniaOrder() {
}
public CaliforniaOrder(double inp_orderAmount,
double inp_additionalTax) {
orderAmount = inp_orderAmount;
additionalTax = inp_additionalTax;
}
public double getOrderAmount() {
return orderAmount;
}
public double getAdditionalTax() {
return additionalTax;
}
public void accept(VisitorInterface v) {
v.visit(this);
}
}
public class NonCaliforniaOrder implements Order {
private double orderAmount;
public NonCaliforniaOrder() {
}
public NonCaliforniaOrder(double inp_orderAmount) {
orderAmount = inp_orderAmount;
}
public double getOrderAmount() {
return orderAmount;
}
public void accept(VisitorInterface v) {
v.visit(this);
}
}
public class OverseasOrder implements Order {
private double orderAmount;
private double additionalSH;
public OverseasOrder() {
}
public OverseasOrder(double inp_orderAmount,
double inp_additionalSH) {
orderAmount = inp_orderAmount;
additionalSH = inp_additionalSH;
}
public double getOrderAmount() {
return orderAmount;
}
public double getAdditionalSH() {
return additionalSH;
}
public void accept(VisitorInterface v) {
v.visit(this);
}
}
|
No comments:
Post a Comment