Visitor Pattern

Pros

  • Allows Double Dispatching
  • Decouples data structures from operations performed on them while also allowing those operations to be dynamically changed

  • Does not break the open/closed principle

Cons

  • When a new visitable class is created all visitors need to be modified so this pattern is better used for classes that won't change

Example Explanation

ElementalDamageVisitor - This class increases the damage of a Mob based on their element through visiting

FireMob/WaterMob/LightningMob - These classes use the visitor to increase their damage

import java.util.Random;

class Main {
  public static void main(String[] args) {

    ElementalDamageVisitor visitor = new ElementalDamageVisitor();

    Mob fire = new FireMob();
    System.out.println( fire.getAttack() );//10
    fire.accept(visitor);
    System.out.println( fire.getAttack() );//13
    System.out.println();

    Mob water = new WaterMob();
    System.out.println( water.getAttack() );//10
    water.accept(visitor);
    System.out.println( water.getAttack() );//12
    System.out.println();

    Mob light = new LightningMob();
    System.out.println( light.getAttack() );//10
    light.accept(visitor);
    System.out.println( light.getAttack() );//randon num between 11 and 15
  }
}
enum Element {
    FIRE,
    WATER,
    LIGHTNING
}

interface IVisitor{
  public void visit(FireMob mob);
  public void visit(WaterMob mob);
  public void visit(LightningMob mob);
}

abstract class Mob {
  protected Element elem;
  private int attack;

  public Mob(Element elem){
    this.elem = elem;
    this.attack = 10;
  }

  public Element getElement(){ return elem; }
  public int getAttack(){ return attack; }
  public void setAttack(int newAttack){ this.attack = newAttack; }

  abstract void accept(IVisitor visitor);

}

class ElementalDamageVisitor implements IVisitor{

  public void visit(FireMob mob){
    //fire mobs get +3 attack
    mob.setAttack( mob.getAttack() + 3 );
  }
  public void visit(WaterMob mob){
    //water mobs get +2 attack
    mob.setAttack( mob.getAttack() + 2 );
  }
  public void visit(LightningMob mob){
    //lightning mobs get +1 to +5 attack
    Random ran = new Random();
    int dmgBoost = ran.nextInt(5) + 1;
    mob.setAttack( mob.getAttack() + dmgBoost );
  }
}

class FireMob extends Mob{

  public FireMob(){
    super(Element.FIRE);
  }
  @Override
  public void accept(IVisitor visitor){visitor.visit(this);}
}

class WaterMob extends Mob{
  public WaterMob(){
    super(Element.WATER);
  }
  @Override
  public void accept(IVisitor visitor){visitor.visit(this);}
}

class LightningMob extends Mob{
  public LightningMob(){
    super(Element.LIGHTNING);
  }
  @Override
  public void accept(IVisitor visitor){visitor.visit(this);}
}

Extra Resources

https://www.tutorialspoint.com/design_pattern/visitor_pattern.htm

https://softwareengineering.stackexchange.com/a/333702/293317

results matching ""

    No results matching ""