Design Patterns: Visitor

The Visitor Design Pattern can be used when you need to perform an action on the object but the logic isn't semantically correct to be placed in that object. So we can have an external object “visit” that instance and call an action to be performed.

In games we could use this pattern on attacks. In the game Breath of Fire IV, for example, there are many types of attacks and various types of creatures. One might recover life instead of taking damage depending on the type of attack. The logic to determine what happens after an attack happens can be isolated on a visitor.

To do that we will need the visitor. The visitor declares a method that requires an object that it will visit. In this example I made one visitor that can access Units.

  1. public interface IVisitor<T> where T: Unit    
  2. {    
  3.     void Visit(T unit);    
  4. }    
  5.      
  6. public class GigaFlare : IVisitor<Unit>    
  7. {    
  8.     public int Damage { getprivate set; }    
  9.      
  10.     public GigaFlare()    
  11.     {    
  12.         Damage = 100;    
  13.     }    
  14.      
  15.     // when we access the unit it will perform action on    
  16.     // the instance that accepts the visit    
  17.     public void Visit(Unit unit)    
  18.     {    
  19.         if (unit.AbsorbsFire)    
  20.         {    
  21.             unit.HealthPoints += Damage;    
  22.         }    
  23.         else    
  24.         {    
  25.             unit.HealthPoints -= Damage - unit.DefensePoints;    
  26.         }    
  27.     }    

And we also need the Unit. The Unit has a method that accepts the visitor and allows the visitor to visit the instance accepting it.

  1. public abstract class Unit    
  2. {    
  3.     public int HealthPoints { getset; }    
  4.      
  5.     public int DefensePoints { getset; }    
  6.      
  7.     public bool AbsorbsFire { getset; }    
  8.      
  9.     // when we accept the instance being visited    
  10.     // is sent to the visitor to perform changes    
  11.     public void Accept(IVisitor<Unit> visitor)    
  12.     {    
  13.         visitor.Visit(this);    
  14.     }    
  15. }    
  16.      
  17. public class Goo : Unit    
  18. {    
  19.     public Goo()    
  20.     {    
  21.         HealthPoints = 100;    
  22.         DefensePoints = 50;    
  23.     }    
  24. }    
  25.      
  26. public class FireGoo : Goo    
  27. {    
  28.     public FireGoo()    
  29.     {    
  30.         AbsorbsFire = true;    
  31.     }    
  32. }  

In short this is what is happening:

  1. visits      accepts            changes    
  2. ------> Unit ------> GigaFlare -------> Unit   

If we now put it to a test:

  1. var goo = new Goo();    
  2. var fgoo = new FireGoo();    
  3.      
  4. var gigaFlare = new GigaFlare();    
  5.      
  6. goo.Accept(gigaFlare);    
  7. fgoo.Accept(gigaFlare);  

The result will be:

  1. 50   // Goo had 50 def and took half the damage    
  2. 200  // FireGoo could absorb fire so it doubled its health   

In another example, similar to this one, is on Starcraft where a siege tank does various amounts of damage to various units. The projectile visit units and handles damage appropriately. A Pattern Craft video from John Lindquist shows it: PatternCraft - Visitor Pattern.

Up Next
    Ebook Download
    View all
    Learn
    View all