Design Pattern / Behavioral

[Design Pattern] Interpreter Pattern

A pattern that interprets small domain language rules through grammar objects and computes a result.

  • Design Pattern
  • Behavioral
Contents

One-line pattern summary

A pattern that interprets small domain language rules through grammar objects and computes a result.

Typical Unity use cases

  • When building a quest condition DSL.
  • When dialogue branch conditions should be data-driven.

Parts (roles)

  • Expression
  • Terminal
  • Nonterminal
  • Context

Unity example (C#)

The code below is a simplified Unity example based on the scenario described above.

public interface IConditionExpression
{
    bool Evaluate(PlayerContext context);
}

public sealed class LevelAtLeastExpression : IConditionExpression
{
    private readonly int requiredLevel;

    public LevelAtLeastExpression(int requiredLevel)
    {
        this.requiredLevel = requiredLevel;
    }

    public bool Evaluate(PlayerContext context)
    {
        return context.PlayerLevel >= requiredLevel;
    }
}

public sealed class AndExpression : IConditionExpression
{
    private readonly IConditionExpression leftExpression;
    private readonly IConditionExpression rightExpression;

    public AndExpression(IConditionExpression leftExpression, IConditionExpression rightExpression)
    {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }

    public bool Evaluate(PlayerContext context)
    {
        return leftExpression.Evaluate(context) && rightExpression.Evaluate(context);
    }
}

Advantages

  • Behavior is separated into smaller units, which reduces the impact of changes.
  • Adding or swapping rules is relatively safe.

Things to watch out for

  • As the number of objects and indirect calls increases, the flow can become harder to follow.
  • Ordering bugs should be pinned down with tests.

Interaction diagram

This shows the flow where grammar rules are interpreted as an expression tree to compute a result.

flowchart LR

  input["Rule String"]
  lexer["Tokenizer"]
  parser["Parser"]
  ast["Expression Tree"]
  interpreter["Interpret(context)"]
  result["bool / score"]

  input --> lexer
  lexer --> parser
  parser --> ast
  ast -->|recursive visit| interpreter
  interpreter --> result

Comments