Что это такое
Паттерн Интерпретатор (Interpreter) вычисляет выражения небольшого языка, строя дерево объектов-выражений — каждый узел знает, как интерпретировать сам себя. Числа интерпретируются в самих себя; узел сложения интерпретирует обе свои части и складывает их.
Он подходит для маленьких языков: фильтров, формул, простых правил. Настоящие языки заслуживают настоящих инструментов разбора.
Пример: крошечный калькулятор
Входная строка 3 + 4 - 2 превращается в дерево из узлов Number, Add и Subtract. Один вызов Interpret() на корне вычисляет всё выражение целиком.
Каждый узел интерпретирует сам себя
parse строит дерево слева направо; Interpret() обходит его. Поддержка * потребовала бы всего одного нового типа узла — существующие остались бы нетронутыми.
Вывод: программа на Go и захваченный вывод
package main
import (
"fmt"
"strconv"
"strings"
)
// Каждый узел знает, как интерпретировать сам себя.
type Expression interface {
Interpret() int
}
type Number struct{ value int }
func (n Number) Interpret() int { return n.value }
type Add struct{ left, right Expression }
func (a Add) Interpret() int { return a.left.Interpret() + a.right.Interpret() }
type Subtract struct{ left, right Expression }
func (s Subtract) Interpret() int { return s.left.Interpret() - s.right.Interpret() }
func parse(input string) Expression {
parts := strings.Fields(input)
n, _ := strconv.Atoi(parts[0])
var expr Expression = Number{n}
for i := 1; i < len(parts); i += 2 {
n, _ := strconv.Atoi(parts[i+1])
if parts[i] == "+" {
expr = Add{expr, Number{n}}
} else {
expr = Subtract{expr, Number{n}}
}
}
return expr
}
func main() {
input := "3 + 4 - 2"
fmt.Println(input, "=", parse(input).Interpret())
}
Когда его использовать
Используйте его, когда пользователи или файлы настроек выражают логику на небольшом языке вашего собственного изобретения: фильтры поиска, формулы расчёта цен, правила проверки.
Откажитесь от него, когда «язык» — это три фиксированных варианта (возьмите switch) или, наоборот, настоящий язык (возьмите генератор парсеров или готовый движок).
Плюсы и минусы
Плюсы: грамматика отображается один к одному на небольшие типы; новые операции — это новые типы узлов; деревья выражений можно строить, проверять и переиспользовать.
Минусы: с ростом грамматики становится всё мучительнее; сам разбор всё равно нужно написать; производительность скромная по сравнению со скомпилированной логикой.