[Serie de patrones de diseño 20] Principio del patrón de intérprete y su incorporación en el código fuente JDK y Spring

Descripción general de la serie de patrones de diseño

Patrones de diseño Boleto aereo
Tres modelos de fábrica Entrada de embarque
Modo de estrategia Entrada de embarque
Modo de delegación Entrada de embarque
Patrón de método de plantilla Entrada de embarque
Modo observador Entrada de embarque
Modo singleton Entrada de embarque
Modo de prototipo Entrada de embarque
Modelo de agencia Entrada de embarque
Modo decorador Entrada de embarque
Modo adaptador Entrada de embarque
Modo constructor Entrada de embarque
Modelo de cadena de responsabilidad Entrada de embarque
Modelo de peso mosca Entrada de embarque
Modo de combinación Entrada de embarque
Patrón de fachada Entrada de embarque
Modo Puente Entrada de embarque
Modelo intermediario Entrada de embarque
Modo iterador Entrada de embarque
Modo de estado Entrada de embarque
Modo intérprete Entrada de embarque
Modo de nota Entrada de embarque
Modo de comando Entrada de embarque
Modo visitante Entrada de embarque
Resumen de 7 principios y patrones de diseño de diseño de software Entrada de embarque

Prefacio

El modo de intérprete significa literalmente que necesitas explicar el significado de algún contenido, pero de hecho esto es exactamente lo que hace el modo de intérprete. Este artículo presentará principalmente el principio del patrón de intérprete, y combinará un ejemplo simple para profundizar nuestra comprensión del patrón de intérprete El patrón de intérprete ya tiene muchas ruedas en nuestra capa de desarrollo de aplicaciones, por lo que reduciremos el número de repeticiones. Haz ruedas.

Que es el modo intérprete

El patrón de intérprete se refiere a un idioma dado, se define una representación de su gramática (como: expresiones de suma, resta, multiplicación y división, expresiones regulares, etc.), y luego se define un intérprete, que se usa para interpretar Nuestra representación gramatical (expresión).

El modo de intérprete es un modo de diseño que se analiza de acuerdo con la gramática prescrita (gramática), que es un modo de comportamiento.

De acuerdo, el momento de fingir ha llegado de nuevo: hablar es barato, mostrarle el código , primero veamos un ejemplo muy simple.

Expresión terminal y expresión no terminal

Hay dos conceptos de expresión terminal y expresión no terminal en el modo de intérprete.

  • Expresión terminal (Expresión terminal): realiza la operación de interpretación relacionada con el símbolo terminal en la gramática. Cada símbolo terminal en la gramática tiene una expresión terminal específica correspondiente. Por ejemplo, en nuestra operación R = M + N, M y N son símbolos terminales, y el intérprete correspondiente que analiza M y N es la expresión terminal.
  • Expresión no terminal (expresión no terminal): realice las operaciones de interpretación relacionadas con los símbolos no terminales en la gramática. Cada regla de la gramática corresponde a una expresión no terminal. Las expresiones no terminales son generalmente operadores o palabras clave en la gramática, como se muestra arriba: el signo "+" en R = M + N es un símbolo no terminal y el intérprete que analiza el signo "+" es una expresión no terminal .

Ejemplo de modo de intérprete

A continuación, escribiremos un ejemplo simple con una clase de expresión de suma y resta simple:
1. Primero, establezca una interfaz de expresión de nivel superior:

package com.zwx.design.pattern.interpreter;

public interface IExpression {
    
    
    int interpret();
}

2. Defina una expresión abstracta no terminal (como los signos más y menos son expresiones no terminales):

package com.zwx.design.pattern.interpreter;

/**
 * 非终结表达式-抽象表达式
 */
public abstract class AbstractNonTerminalExpression implements IExpression{
    
    
    protected IExpression leftExpression;
    protected IExpression rightExpression;

    public AbstractNonTerminalExpression(IExpression leftExpression, IExpression rightExpression) {
    
    
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }
}

3. Debido a que este ejemplo solo enumera la suma y la resta, también necesitamos una clase de suma y una clase de resta:

package com.zwx.design.pattern.interpreter;

/**
 * 非终结表达式-具体表达式-加法表达式
 */
public class AddExpression extends AbstractNonTerminalExpression {
    
    
    public AddExpression(IExpression leftExpression, IExpression rightExpression) {
    
    
        super(leftExpression, rightExpression);
    }

    @Override
    public int interpret() {
    
    
        return this.leftExpression.interpret() + this.rightExpression.interpret();
    }
}
package com.zwx.design.pattern.interpreter;

/**
 * 非终结表达式-具体表达式-减法表达式
 */
public class SubExpression extends AbstractNonTerminalExpression {
    
    

    public SubExpression(IExpression leftExpression, IExpression rightExpression) {
    
    
        super(leftExpression, rightExpression);
    }

    @Override
    public int interpret() {
    
    
        return this.leftExpression.interpret() - this.rightExpression.interpret();
    }
}

4. Cree una expresión final (como el valor en la suma y la resta):

package com.zwx.design.pattern.interpreter;

/**
 * 终结表达式-数值表达式
 */
public class NumberExpression implements IExpression{
    
    
    private int value;

    public NumberExpression(String value) {
    
    
        this.value = Integer.valueOf(value);
    }

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

5. Finalmente, también necesitamos información contextual para almacenar los resultados de nuestros cálculos:

package com.zwx.design.pattern.interpreter;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class ExpressionContext {
    
    
    private Integer currValue;//记录当前运算结果,空表示暂未运算
    private Stack<IExpression> stack = new Stack<>();

    public ExpressionContext(String expression) {
    
    
        this.parse(expression);
    }

    private void parse(String expression) {
    
    
        String[] elementArr = expression.split(" ");
        for (int i=0;i<elementArr.length;i++){
    
    
            String element = elementArr[i];
            if (element.equals("+")){
    
    
                IExpression leftExpression = stack.pop();//栈内元素出栈
                IExpression rightExpression = new NumberExpression(elementArr[++i]);//取出+号后的下一个元素
                IExpression addExpression = new AddExpression(leftExpression,rightExpression);
                stack.push(new NumberExpression(addExpression.interpret() + ""));//将计算结果入栈
            }else if (element.equals("-")){
    
    
                IExpression leftExpression = stack.pop();//栈内元素出栈
                IExpression rightExpression = new NumberExpression(elementArr[++i]);//取出-号后的下一个元素
                IExpression subExpression = new SubExpression(leftExpression,rightExpression);
                stack.push(new NumberExpression(subExpression.interpret() + ""));//将计算结果入栈
            }else{
    
    
                stack.push(new NumberExpression(element));//如果是数字则直接入栈
            }
        }
    }

    public int calcuate(){
    
    
        return stack.pop().interpret();//经过前面解析,到这里stack内只会剩下唯一一个数字,即运算结果
    }
}

6. Finalmente, cree una nueva clase de prueba para probar:

package com.zwx.design.pattern.interpreter;

public class TestInterpreter {
    
    
    public static void main(String[] args) {
    
    
        ExpressionContext context = new ExpressionContext("666 + 888 - 777");
        System.out.println(context.calcuate());
        context = new ExpressionContext("123 - 456 + 11");
        System.out.println(context.calcuate());

    }
}

El resultado de ejecución es:

777
-322

Rol del modo intérprete

Del ejemplo anterior, podemos concluir que el modo de intérprete tiene principalmente 4 roles:

  • Expresión abstracta (Expresión): generalmente, se define un método de interpretación y la forma de analizarlo se implementará mediante subclases (como IExpression en el ejemplo).
  • Expresión terminal (expresión terminal): realice la operación de interpretación relacionada con el símbolo terminal en la gramática (como AddExpression, SubExpression en el ejemplo).
  • Expresión no terminal: implemente operaciones de interpretación relacionadas con símbolos no terminales en la gramática (como NumberExpression en el ejemplo).
  • Contexto: contiene información global fuera del intérprete. Generalmente se usa para almacenar el valor específico correspondiente a cada símbolo de terminal en la gramática.

El modo de intérprete se aplica en el código fuente JDK y Spring

Todos deberían poder adivinar la aplicación de esto en el código fuente, como la expresión regular en la clase JDK: Pattern. También existe la interfaz ExpressionParse en Spring. No sé si ha usado esta expresión en Spring. De hecho, también puede realizar sumas, restas, multiplicaciones y divisiones. El siguiente es un ejemplo de aplicación simple:
Inserte la descripción de la imagen aquí
como mencionamos al principio, generalmente usamos relativamente poco este modo de intérprete en el desarrollo comercial, y algunas expresiones comunes se han analizado directamente para nosotros. Úselo, a menos que estemos involucrados en un desarrollo de bajo nivel y necesitemos definir expresiones más complejas.

Escenarios de aplicación del modo de intérprete

El modo de intérprete se puede utilizar principalmente en los siguientes escenarios:

  • 1. Cuando tenemos algunos problemas que necesitan un análisis repetido, podemos considerar definir una expresión para expresar.
  • 2. Si necesita explicar algo de gramática simple, también puede considerar el modo de intérprete.

Ventajas y desventajas del modo intérprete

ventaja:

  • 1. La escalabilidad es relativamente fuerte. Como se puede ver en nuestro ejemplo anterior, cada una de nuestras expresiones es una clase, por lo que si necesita modificar una regla determinada, solo necesita modificar la clase de expresión correspondiente.Puede agregar una nueva clase al expandir. Arriba.

Desventaja

  • 1. Cuando las reglas gramaticales son más complicadas, provocará una expansión de la clase, que es más difícil de mantener.
  • 2. Cuando las reglas gramaticales son más complicadas, si algo sale mal, la depuración es más difícil.
  • 3. La eficiencia de ejecución es relativamente baja. Porque cuando la expresión es más complicada, el resultado se analizará de forma recursiva si el resultado tiene capas.

para resumir

Este artículo presenta principalmente el uso básico del patrón de intérprete y utiliza un ejemplo simple para ayudar a comprender mejor el patrón de intérprete. Por supuesto, este ejemplo es relativamente simple de escribir y no se consideran muchas lógicas de negocios, pero estos no son el tema central de este artículo. , El enfoque de este artículo es presentar la idea del modo de intérprete. Finalmente, también presentamos la incorporación del modo de intérprete en el código fuente relevante de JDK. Espero que a través de este artículo, pueda tener una comprensión más profunda de las ideas de diseño del modo de intérprete.

Por favor, prestame atención y aprende y progresa con el lobo solitario .

Supongo que te gusta

Origin blog.csdn.net/zwx900102/article/details/109253256
Recomendado
Clasificación