likes
comments
collection
share

通俗易懂设计模式(解释器模式)

作者站长头像
站长
· 阅读数 29

解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于定义一个语言的文法,并提供一个解释器来解释这个语言中的句子。解释器模式的主要目的是将一个复杂的语言或表达式的解释过程拆分成多个小的、可组合的部分,从而使得语言或表达式的解释变得更加灵活和可扩展。

解释器模式的主要组成部分包括:

  1. 抽象表达式(AbstractExpression):定义了一个抽象类或接口,用于表示语言中的一个表达式。抽象表达式通常包含一个 interpret() 方法,用于解释表达式的含义。
  2. 终结表达式(TerminalExpression):实现了抽象表达式接口,用于表示语言中的一个终结符。终结表达式通常包含一个值,用于表示该终结符的含义。
  3. 非终结表达式(NonterminalExpression):实现了抽象表达式接口,用于表示语言中的一个非终结符。非终结表达式通常包含多个子表达式,用于表示该非终结符的含义。
  4. 上下文(Context):用于存储解释器所需的上下文信息,例如变量的值、函数的定义等。上下文通常作为参数传递给抽象表达式的 interpret() 方法,以便表达式在解释时可以访问这些信息。
  5. 客户端(Client):负责创建语言中的句子,并调用解释器来解释这些句子。客户端可以是任何类,只要它能够创建和组合这些句子。

Java 实现解释器模式的示例代码:

// 抽象表达式接口
public interface Expression {
    boolean interpret(Context context);
}

// 终结表达式类
public class TerminalExpression implements Expression {
    private String variable;

    public TerminalExpression(String variable) {
        this.variable = variable;
    }

    @Override
    public boolean interpret(Context context) {
        return context.lookup(variable);
    }
}

// 非终结表达式类
public class NonterminalExpression implements Expression {
    private Expression left;
    private Expression right;

    public NonterminalExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean interpret(Context context) {
        return left.interpret(context) && right.interpret(context);
    }
}

// 上下文类
public class Context {
    private Map<String, Boolean> variables = new HashMap<>();

    public void assign(String variable, boolean value) {
        variables.put(variable, value);
    }

    public boolean lookup(String variable) {
        return variables.getOrDefault(variable, false);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.assign("A", true);
        context.assign("B", false);

        Expression expression1 = new TerminalExpression("A");
        Expression expression2 = new TerminalExpression("B");
        Expression expression3 = new NonterminalExpression(expression1, expression2);

        System.out.println("A && B = " + expression3.interpret(context));
    }
}

在这个示例中,我们定义了一个抽象表达式接口 Expression,它包含了一个 interpret() 方法。接着,我们定义了一个终结表达式类 TerminalExpression,它实现了 Expression 接口,并在其中定义了一个变量。在终结表达式类的 interpret() 方法中,我们根据上下文中的变量值来解释表达式的含义。

接着,我们定义了一个非终结表达式类 NonterminalExpression,它实现了 Expression 接口,并在其中定义了两个子表达式。在非终结表达式类的 interpret() 方法中,我们递归地解释子表达式的含义,并将它们组合起来。

接着,我们定义了一个上下文类 Context,它用于存储解释器所需的上下文信息。在上下文类中,我们定义了一个 variables 字典,用于存储变量的值。然后,我们定义了 assign()lookup() 方法,用于分配和查找变量的值。

在客户端代码中,我们创建了一个上下文对象,并为其分配了变量的值。然后,我们创建了一个终结表达式对象和一个非终结表达式对象,并将它们组合在一起。最后,我们调用非终结表达式对象的 interpret() 方法,并传入上下文对象,以解释表达式的含义。通过这种方式,我们将表达式的解释过程拆分成多个小的、可组合的部分,从而使得表达式的解释变得更加灵活和可扩展。

场景举例

场景一:编译器和解释器

解释器模式可以用于实现编译器和解释器。在这种情况下,解释器模式可以将源代码解析成抽象语法树(AST),然后遍历抽象语法树来执行代码。

以下是一个简单的解释器模式示例,用于计算表达式的值:

首先,我们定义一个Expression接口,表示表达式:

public interface Expression {
    int interpret();
}

接下来,我们实现两个具体的表达式类NumberExpressionAddExpression,分别表示数字和加法表达式:

public class NumberExpression implements Expression {
    private int value;

    public NumberExpression(int value) {
        this.value = value;
    }

    @Override
    public int interpret() {
        return value;
    }
}

public class AddExpression implements Expression {
    private Expression left;
    private Expression right;

    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

然后,我们创建一个ExpressionParser类,用于解析表达式字符串并构建抽象语法树:

public class ExpressionParser {
    private String expression;
    private int index;

    public ExpressionParser(String expression) {
        this.expression = expression;
    }

    public Expression parse() {
        return parseExpression();
    }

    private Expression parseExpression() {
        Expression left = parseTerm();
        while (index< expression.length() && expression.charAt(index) == '+') {
            index++;
            Expression right = parseTerm();
            left = new AddExpression(left, right);
        }
        return left;
    }

    private Expression parseTerm() {
        int start = index;
        while (index< expression.length() && Character.isDigit(expression.charAt(index))) {
            index++;
        }
        return new NumberExpression(Integer.parseInt(expression.substring(start, index)));
    }
}

在客户端,我们使用ExpressionParser解析表达式字符串,并通过解释器执行表达式:

public class Client {
    public static void main(String[] args) {
        String expression = "1+2+3";
        ExpressionParser parser = new ExpressionParser(expression);
        Expression ast = parser.parse();
        int result = ast.interpret();
        System.out.println("Result: " + result);
    }
}

在这个例子中,我们使用解释器模式实现了一个简单的表达式解释器。解释器将表达式字符串解析成抽象语法树,然后遍历抽象语法树来计算表达式的值。

场景二:正则表达式

解释器模式也可以用于实现正则表达式引擎。在这种情况下,解释器模式可以将正则表达式解析成抽象语法树(AST),然后遍历抽象语法树来匹配字符串。

以下是一个简单的解释器模式示例,用于匹配字符串是否符合正则表达式:

首先,我们定义一个RegexExpression接口,表示正则表达式:

public interface RegexExpression {
    boolean interpret(String input);
}

接下来,我们实现两个具体的正则表达式类CharExpressionConcatExpression,分别表示字符和连接表达式:

public class CharExpression implements RegexExpression {
    private char c;

    public CharExpression(char c) {
        this.c = c;
    }

    @Override
    public boolean interpret(String input) {
        return input.length() == 1 && input.charAt(0) == c;
    }
}

public class ConcatExpression implements RegexExpression {
    private RegexExpression left;
    private RegexExpression right;

    public ConcatExpression(RegexExpression left, RegexExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean interpret(String input) {
        for (int i = 0; i< input.length(); i++) {
            String leftInput = input.substring(0, i);
            String rightInput = input.substring(i);
            if (left.interpret(leftInput) && right.interpret(rightInput)) {
                return true;
            }
        }
        return false;
    }
}

然后,我们创建一个RegexParser类,用于解析正则表达式字符串并构建抽象语法树:

public class RegexParser {
    private String regex;
    private int index;

    public RegexParser(String regex) {
        this.regex = regex;
    }

    public RegexExpression parse() {
        return parseConcat();
    }

    private RegexExpression parseConcat() {
        RegexExpression left = parseChar();
        while (index< regex.length() && regex.charAt(index) != '|') {
            RegexExpression right = parseChar();
            left = new ConcatExpression(left, right);
        }
        return left;
    }

    private RegexExpression parseChar() {
        char c = regex.charAt(index);
        index++;
        return new CharExpression(c);
    }
}

在客户端,我们使用RegexParser解析正则表达式字符串,并通过解释器检查字符串是否符合正则表达式:

public class Client {
    public static void main(String[] args) {
        String regex = "abc";
        RegexParser parser = new RegexParser(regex);
        RegexExpression ast = parser.parse();
        String input = "abc";
        boolean result = ast.interpret(input);
        System.out.println("Result: " + result);
    }
}

在这个例子中,我们使用解释器模式实现了一个简单的正则表达式引擎。解释器将正则表达式字符串解析成抽象语法树,然后遍历抽象语法树来检查字符串是否符合正则表达式。

转载自:https://juejin.cn/post/7342718848817348620
评论
请登录