Visitor
The visitor pattern
The visitor pattern is a behavioral pattern and a little unusual it that it allows modifying the behaviour of many structures without altering the code of the structures.It needs either prior knowledge or altering the underlying abstraction, by adding a method that accepts the visitor.
The image below shows the visitor pattern and it's quite complex:
An interface for Equipment:
interface Equipment {
int NetPrice();
int DiscountPrice();
// other class members ...
void Accept(EquipmentVisitor equipmentVisitor);
}
Importantly, observe the void Accept(EquipmentVisitor equipmentVisitor),
has a reference to an abstraction, EquipmentVisitor.int NetPrice();
int DiscountPrice();
// other class members ...
void Accept(EquipmentVisitor equipmentVisitor);
}
The abstraction being:
interface EquipmentVisitor {
void Visit(Equipment equipment);
}
And a few implementations of the Equipment interface:
void Visit(Equipment equipment);
}
class Chassis : Equipment {
public void Accept(EquipmentVisitor equipmentVisitor) {
equipmentVisitor.Visit(this);
}
public int DiscountPrice() {
return 99;
}
public int NetPrice() {
return 101;
}
}
public void Accept(EquipmentVisitor equipmentVisitor) {
equipmentVisitor.Visit(this);
}
public int DiscountPrice() {
return 99;
}
public int NetPrice() {
return 101;
}
}
class FloppyDisk : Equipment {
public void Accept(EquipmentVisitor equipmentVisitor) {
equipmentVisitor.Visit(this);
}
public int DiscountPrice() {
return 15;
}
public int NetPrice() {
return 20;
}
}
public void Accept(EquipmentVisitor equipmentVisitor) {
equipmentVisitor.Visit(this);
}
public int DiscountPrice() {
return 15;
}
public int NetPrice() {
return 20;
}
}
class Bus : Equipment {
public void Accept(EquipmentVisitor equipmentVisitor) {
equipmentVisitor.Visit(this);
}
public int DiscountPrice() {
return 3;
}
public int NetPrice() {
return 4;
}
}
We then implement the EquipmentVisitor interface:
public void Accept(EquipmentVisitor equipmentVisitor) {
equipmentVisitor.Visit(this);
}
public int DiscountPrice() {
return 3;
}
public int NetPrice() {
return 4;
}
}
class PricingVisitor : EquipmentVisitor {
private int currentTotal = 0;
public int GetTotalPrice() {
return currentTotal;
}
public void Visit(Equipment equipment) {
currentTotal += equipment.NetPrice();
}
}
The code to run this example:
private int currentTotal = 0;
public int GetTotalPrice() {
return currentTotal;
}
public void Visit(Equipment equipment) {
currentTotal += equipment.NetPrice();
}
}
static void Main(string[] args) {
Equipment floppyDisk = new FloppyDisk();
Equipment chassis = new Chassis();
Equipment bus = new Bus();
PricingVisitor pricingVisitor = new PricingVisitor();
floppyDisk.Accept(pricingVisitor);
chassis.Accept(pricingVisitor);
bus.Accept(pricingVisitor);
Console.WriteLine("The total price of the equipment is {0} plutonomites", pricingVisitor.GetTotalPrice());
Console.ReadKey();
}
The output of the console:
Equipment floppyDisk = new FloppyDisk();
Equipment chassis = new Chassis();
Equipment bus = new Bus();
PricingVisitor pricingVisitor = new PricingVisitor();
floppyDisk.Accept(pricingVisitor);
chassis.Accept(pricingVisitor);
bus.Accept(pricingVisitor);
Console.WriteLine("The total price of the equipment is {0} plutonomites", pricingVisitor.GetTotalPrice());
Console.ReadKey();
}
The total price of the equipment is 125 plutonomites
Summary
Eventhough my example above is incredibly convoluted and doesn't really do the visitor pattern justice it's a great pattern if you want to change the behavior of an existing class and prevent adding multiple methods to the class, you can add the visitor and then carry out different actions implemented from different visitors.