Skip to content

Visitor Pattern

Aprius edited this page Nov 9, 2024 · 6 revisions

What

Wikipedia's defintion of the visitor pattern:

A visitor pattern is a software design pattern that separates the algorithm from the object structure. Because of this separation, new operations can be added to existing object structures without modifying the structures. It is one way to follow the open/closed principle in object-oriented programming and software engineering.

Usage

In RPG game:

  • Healing items can restore health to characters
  • Damage effects can deal damage to enemies

Using the Visitor pattern, we can implement these behaviors without modifying the component classes.

1, Define class visitable, Player and Enemy both implement IVisitable and have methods for taking damage or healing.

using Pancake.Pattern;
using UnityEngine;

public class Player : MonoBehaviour, IVisitable
{
    public int hp = 100;

    public void Accept(IVisitor visitor) { visitor.Visit(this); }

    public void Heal(int amount)
    {
        hp += amount;
        Debug.Log($"Player healed by {amount}. Current Health: {hp}");
    }

    public void TakeDamage(int amount)
    {
        hp -= amount;
        Debug.Log($"Player took {amount} damage. Current Health: {hp}");
    }
}
using Pancake.Pattern;
using UnityEngine;

public class Enemy : MonoBehaviour, IVisitable
{
    public int hp = 100;

    public void Accept(IVisitor visitor) { visitor.Visit(this); }

    public void Heal(int amount)
    {
        hp += amount;
        Debug.Log($"Enemy healed by {amount}. Current Health: {hp}");
    }

    public void TakeDamage(int amount)
    {
        hp -= amount;
        Debug.Log($"Enemy took {amount} damage. Current Health: {hp}");
    }
}

2, Create Specific Visitor Classes for Healing and Damage

  • HealingVisitor heals the Player by a specified amount.
  • DamageVisitor applies damage to both Player and Enemy`.
using Pancake.Pattern;
using UnityEngine;

public class HealingVisitor : IVisitor
{
    private int _healingAmount;

    public HealingVisitor(int healingAmount) { _healingAmount = healingAmount; }

    public void Visit<T>(T visitable) where T : Component, IVisitable
    {
        if (visitable is Player player) player.Heal(_healingAmount);
    }
}
using Pancake.Pattern;
using UnityEngine;

public class DamageVisitor : IVisitor
{
    private int _damage;

    public DamageVisitor(int damage) { _damage = damage; }

    public void Visit<T>(T visitable) where T : Component, IVisitable
    {
        if (visitable is Player player)
        {
            player.TakeDamage(_damage);
        }
        else if (visitable is Enemy enemy)
        {
            enemy.TakeDamage(_damage * 2);
        }
    }
}

3,

using Pancake.Pattern;
using UnityEngine;

public class Demo : MonoBehaviour
{
    public Enemy enemy;
    public Player player;
    
    private void Start()
    {
        IVisitor healingVisitor = new HealingVisitor(20);
        IVisitor damageVisitor = new DamageVisitor(15);
        
        player.Accept(healingVisitor); // Heal only the player
        
        enemy.Accept(damageVisitor);
        player.Accept(damageVisitor);
    }
}

image

Clone this wiki locally