浅谈设计模式-解释器模式

本文深入介绍了解释器模式,通过一个加减乘除运算的实例展示了如何设计和实现一个解析器。文章详细阐述了模式的定义、UML类图以及其实现步骤,包括定义Expression接口、各个表达式解析器类和终端表达式类。最后,通过一个完整的加减乘除运算例子,解释了如何利用解释器模式解析复杂的运算表达式,实现了计算逻辑。
摘要由CSDN通过智能技术生成

书接上回,本篇讲一下行为型模式-解释器模式

解释器模式

定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

大白话:设计一个程序,能解析拥有一定规则的表达式。比如正则表达式解析器。

UML图

Expression:定义语法解析器的接口,约定解析器的解释操作

/**
 * 语法表达式
 */
public interface Expression {
    /**
     * 语法解析
     */
    void interpret();
}

Interpret1Expression/Interpret2Expression:表达式解析器,解析表达式中特定语法,一个解析器对应一个语法规则。

/**
 * 子表达式(解析1)
 *  负责完整表达式中一段解析
 */
public class Interpret1Expression implements  Expression{
    @Override
    public void interpret() {
        System.out.println("解析表达式中一段:子表达式1");
    }
}
/**
 * 子表达式(解析2)
 *  负责完整表达式中一段解析
 */
public class Interpret2Expression implements  Expression{
    @Override
    public void interpret() {
        System.out.println("解析表达式中一段:子表达式2");
    }
}

TerminalExpression:也是一个表达式解析器,一般表示终结,得出结果的语法,比如四则运算中,最后等于操作。

/**
 * 子表达式(解析3)
 *  负责完整表达式中一段解析--表示解析终止
 */
public class TerminalExpression implements  Expression{
    @Override
    public void interpret() {
        System.out.println("解析表达式中一段:终止表达式");
    }
}

ExpressionInterpretParser:语法表达式解析器,这这个类中调用其他子解析器完整解析整个语法表达式式。担当总控的角色。

/**
 * 表达式解析器
 */
public class ExpressionInterpretParser {
    /**
     * 指定表达式解析
     * @param express
     */
    public void parse(String express){
        System.out.println("表达式:" + express);

        System.out.println("调用解析器:" );
        new Interpret1Expression().interpret();
        new Interpret2Expression().interpret();
        new TerminalExpression().interpret();
    }
}

App:客户端,上面逻辑调用者。

public class App {

    public static void main(String[] args) {
        ExpressionInterpretParser interpret = new ExpressionInterpretParser();
        interpret.parse("这是一个表达式");
    }
}

结果:

表达式:这是一个表达式
调用解析器:
解析表达式中一段:子表达式1
解析表达式中一段:子表达式2
解析表达式中一段:终止表达式

案例分析

需求:设计一个解析器,能解析加减乘除运算

最终表达式:1 2 3 4 5 + - * /

预想结果: (((1+2)-3) *4) / 5 = 0

Expression:定义解析解析语法规则

SubExpression / MulExpression / DivExpression / AddExpression:分别是加减乘除语法解析规则实现

NumExpression:数字语法解析规则实现

ExpressionInterpretParser:规则解析器

App:客户端

具体解析规则类:

AddExpression

//加法
public class AddExpression implements Expression{

    private Expression num1Expression;   //第一个加数
    private Expression num2Expression;   //第二个加数

    public AddExpression(Expression num1Expression, Expression num2Expression){
        this.num1Expression = num1Expression;
        this.num2Expression = num2Expression;
    }
    @Override
    public int interpret() {
        return num1Expression.interpret() + num2Expression.interpret();
    }
    @Override
    public String toString() {
        return "+";
    }
}

SubExpression

//减法
public class SubExpression implements Expression{

    private Expression num1Expression;   //第一个减数
    private Expression num2Expression;   //第二个减数

    public SubExpression(Expression num1Expression, Expression num2Expression){
        this.num1Expression = num1Expression;
        this.num2Expression = num2Expression;
    }
    @Override
    public int interpret() {
        return num1Expression.interpret() - num2Expression.interpret();
    }
    @Override
    public String toString() {
        return "-";
    }
}

MulExpression

//乘法
public class MulExpression implements Expression{

    private Expression num1Expression;   //第一个乘数
    private Expression num2Expression;   //第二个乘数

    public MulExpression(Expression num1Expression, Expression num2Expression){
        this.num1Expression = num1Expression;
        this.num2Expression = num2Expression;
    }

    @Override
    public int interpret() {
        return num1Expression.interpret() * num2Expression.interpret();
    }
    @Override
    public String toString() {
        return "*";
    }
}

DivExpression

//乘法
public class DivExpression implements Expression{

    private Expression num1Expression;   //第一个除数
    private Expression num2Expression;   //第二个除数

    public DivExpression(Expression num1Expression, Expression num2Expression){
        this.num1Expression = num1Expression;
        this.num2Expression = num2Expression;
    }
    @Override
    public int interpret() {
        return num1Expression.interpret() / num2Expression.interpret();
    }
    @Override
    public String toString() {
        return "/";
    }
}

ExpressionInterpretParser


public class ExpressionInterpretParser {


    private LinkedList<Expression> list = new LinkedList<>();

    private boolean isSymbol(String sy){
        return  "+".equals(sy) || "-".equals(sy) || "*".equals(sy)|| "/".equals(sy);
    }

    private Integer operation(Expression num1, Expression num2, String symbol){
        if("+".equals(symbol)){
            return new AddExpression(num1,num2).interpret();
        }else if("-".equals(symbol)){
            return new SubExpression(num1,num2).interpret();
        }else if("*".equals(symbol)){
            return new MulExpression(num1,num2).interpret();
        }else if("/".equals(symbol)){
            return new DivExpression(num1,num2).interpret();
        }

        return null;

    }
    public void parse(String express){
        String[] items = express.split(" ");
        for (String item : items) {
            if(!this.isSymbol(item)){
                list.addLast(new NumExpression(item));
                System.out.println("入栈参数:" + item);
            }else{
                System.out.println("运算符:" + item);
                Expression num1 = list.removeFirst();
                Expression num2 = list.removeFirst();
                Integer ret = this.operation(num1, num2, item);
                if(ret == null){
                    System.out.println("表达式解析异常,无法运算");
                    return;
                }
                this.list.push(new NumExpression(ret));
                System.out.println("运算结果再入栈:" + ret);
            }
        }

        if(list.size() == 1){
            System.out.println("表达式运算结果:" + list.removeFirst());
        }
    }
}

App

public class App {
    public static void main(String[] args) {
        new ExpressionInterpretParser().parse("1 2 3 4 5 + - * /");
    }
}

结果

入栈参数:1
入栈参数:2
入栈参数:3
入栈参数:4
入栈参数:5
运算符:+
运算结果再入栈:3
运算符:-
运算结果再入栈:0
运算符:*
运算结果再入栈:0
运算符:/
运算结果再入栈:0
表达式运算结果:0

解析

加减乘除规则解析类,实现+-*/四则运算逻辑,将计算出结果重新入队列,参与后续计算。

适用场景

一些规则引擎解析

一些确定语法表达式需要解析时

一些重复出现的问题可以用一种简单的语言来进行表达。

优缺点

优点

语法由很多类表示,容易改变及扩展,新增表达式时,只需要添加新的表达式实现类即可,“开闭原则”。

缺点

当语法规则数目太多时,增加系统复杂度


开发案例

Spring自带了SpEl表达式

public class SpringELTest {

    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("(((1+2)-3) *4) / 5 ");
        System.out.println(expression.getValue());
    }
}

类体系:

解析体系类:ExpressionParser

public interface ExpressionParser {
    Expression parseExpression(String expressionString) throws ParseException;
    Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}

解析器实现类:SpelExpressionParser

public class SpelExpressionParser extends TemplateAwareExpressionParser {

    @Override
	protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
		return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
	}

}

父类解析器

public abstract class TemplateAwareExpressionParser implements ExpressionParser {	

    private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
		if (expressionString.isEmpty()) {
			return new LiteralExpression("");
		}

		Expression[] expressions = parseExpressions(expressionString, context);
		if (expressions.length == 1) {
			return expressions[0];
		}
		else {
			return new CompositeStringExpression(expressionString, expressions);
		}
	}

}

解析之后结果对象:Expression

public interface Expression {
    //表达式规则
	String getExpressionString();
    //解析完后结果
	@Nullable
	Object getValue() throws EvaluationException;

}

总结

解析器模式在特定领域,特定场景下才使用,相对其他模式来说,使用频率不高得设计模式啦。

最后来总结一下:

解析器模式的本质:分离实现,解释执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪飞yes

我对钱没兴趣~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值