解释器模式的简单使用

21 篇文章 0 订阅
19 篇文章 0 订阅

前言

解释器模式使用频率比较少,顾名思义解释器模式就是给定一个语言,定义它的语法,然后解释器根据协议来解释这个语言,得到结果。类似于翻译吧。我觉得用的最多的就是计算表达式了:“A+B”,解释器就是按着操作符区分变量和运算符,然后得到A+B的结果。

适用模式

某个语言需要解析执行,比如解析XML之类的,可以用到解释器模式。再者如果特定场景不断重复这个场景,可以提取语法,抽象出解释其模式。

角色扮演

AbstractExpression: 抽象表达式,定义一个抽象解释方法,子类来实现这个解释方法。
TerminalExpression: 终结符表达式,实现语句里与终结符有关的操作。
NoTerminalExpression:与终结符表达式对应,其实不用在意这个解释,其实就会解释器对不同类型的数据进行不同的处理,仅此而已。

Demo实现:

我们抽象出一个Demo,用于计算表达式“a + b - c”,为了简单拆分表达式的元素,我们以空格为表达式分隔符。
AbstractExpression抽象类:

package com.demo.interpreter;

/**
 * Created by Daybreak on 2017/12/19.
 */

public abstract class AbstractExpression {
    /**
     * 提取解释器公用方法
     * @return 解析结果
     */
    public abstract int result();
}

下面我们来定义一个类型,处理数字:

package com.demo.interpreter;

/**
 * Created by Daybreak on 2017/12/19.
 */

public class NumberExpression extends AbstractExpression {
    private int number;

    public NumberExpression(int num){
        this.number = num;
    }

    @Override
    public int result() {
        return number;
    }
}

下面因为表达式分为加减乘除,所以在抽象一个基础类,计算A、B之间的运算:

package com.demo.interpreter;

/**
 * Created by Daybreak on 2017/12/19.
 */

public abstract class AbstractOperationExpression extends AbstractExpression {
    protected AbstractExpression expression1;
    protected AbstractExpression expression2;

    public void setExpression1(AbstractExpression expression1) {
        this.expression1 = expression1;
    }

    public void setExpression2(AbstractExpression expression2) {
        this.expression2 = expression2;
    }
}

下面我们简单实现数据的加和减,乘除的逻辑大同小异。
加法计算类:

package com.demo.interpreter;

/**
 * Created by Daybreak on 2017/12/19.
 */

public class AddExpression extends AbstractOperationExpression {

    public AddExpression(AbstractExpression expression1,AbstractExpression expression2){
        setExpression1(expression1);
        setExpression2(expression2);
    }

    @Override
    public int result() {
        return expression1.result() + expression1.result();
    }
}

减法实现类:

package com.demo.interpreter;

/**
 * Created by Daybreak on 2017/12/19.
 */

public class SubExpression extends AbstractOperationExpression {

    public SubExpression(AbstractExpression expression1,AbstractExpression expression2){
        setExpression1(expression1);
        setExpression2(expression2);
    }

    @Override
    public int result() {
        return expression1.result() - expression2.result();
    }
}

为了使用方便,我们要定义一个工具类,这个工具类就是Client调用方法,调用的时候很简单:

package com.demo.interpreter;

import java.util.Stack;

/**
 * Created by Daybreak on 2017/12/19.
 */

public class OperationTools {
    // 维护一个栈,用于存表达式字符串
    private Stack<AbstractExpression> mAbstractExpressionStack = new Stack<>();

    public int operationExpression(String expression){
        AbstractExpression expression1;
        AbstractExpression expression2;

        // 根据具体协议来拆分字符串,规定了数字与运算符必须以空格隔开,
        // 正常情况下可以用正则表达式来区分
        String[] expressions = expression.split(" ");

        // 循环遍历计算
        for(int i = 0; i < expressions.length; i++){
            String exp = expressions[i].trim();
            switch (exp){
                case "+":
                    // 取出栈顶元素当表达式1
                    expression1 = mAbstractExpressionStack.pop();
                    // 同时取出下一个字符,当表达式2
                    expression2 = new NumberExpression(Integer.valueOf(expressions[++i].trim()));
                    // 把结果当做表示式的第一位,从而继续运算
                    mAbstractExpressionStack.push(new AddExpression(expression1,expression2));
                    break;

                case "-":
                    // 取出栈顶元素当表达式1
                    expression1 = mAbstractExpressionStack.pop();
                    // 同时取出下一个字符,当表达式2
                    expression2 = new NumberExpression(Integer.valueOf(expressions[++i].trim()));
                    // 把结果当做表示式的第一位,从而继续运算
                    mAbstractExpressionStack.push(new SubExpression(expression1,expression2));
                    break;

                default:
                    // 不是运算符,那就是数字
                    mAbstractExpressionStack.push(new NumberExpression(Integer.valueOf(expressions[i].trim())));
                    break;
            }
        }

        // 循环结束,返回结果。
        return mAbstractExpressionStack.pop().result();
    }
}

下面是使用过程,Client类为Activity:

package com.demo.interpreter;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.example.daybreak.helloword.R;

public class InterpreterActivity extends AppCompatActivity {
    private EditText mExpressions = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_interpreter);
        mExpressions = (EditText) findViewById(R.id.expressions);
        findViewById(R.id.result).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // demo先不考虑容错,并规定了数字与运算符必须以空格隔开,正常情况下可以用正则表达式来区分
                int result = new OperationTools().operationExpression(mExpressions.getText().toString());
                Toast.makeText(InterpreterActivity.this,"执行结果 :" + result,Toast.LENGTH_LONG).show();
            }
        });
    }
}

这样,程序就能够简单的计算类似于“12 + 2 - 3”这类语句了。

后记

解释器的优点就是如上的扩展性,要加运算符只需要实现AbstractOperationExpression,当然缺点就是对于每一个语句都有不同的解释器,类的数量就增多了,而且对于复杂的解释行为,难以维护其抽象类,所以这个模式对于简单的语句,使用起来还是很好的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值