当前位置: 首页 > news >正文

Java设计模式之解释器模式

目录

  • 1. 解释器模式
    • 1.1 定义、优缺点、适应场景
    • 1.2 模式的结构与实现

1. 解释器模式

1.1 定义、优缺点、适应场景

定义:解释器模式(Interpreter Pattern),是指给定一个语言(表达式),来表示它的文法,并定义一个解释器,使用该解释器来解释语言中的句子(表达式),并得到结果。例如在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建成一颗抽象语法分析树。这里的词法分析器和语法分析器都可以看做是解释器

优点

  • 易于扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来扩展文法
  • 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言
  • 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合开闭原则

缺点

  • 解释器模式会引起类膨胀
  • 解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低

适应场景

  • 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树,让程序具有良好的扩展性
  • 一些重复出现的问题可以用一种简单的语言来表达
  • 一个简单语法需要解释的场景
  • 比如编译器、运算表达式计算、正则表达式、机器人等

1.2 模式的结构与实现

结构

  • 环境角色(Context): 含有解释器之外的全局信息
  • 抽象表达式(AbstractExpression): 声明一个抽象的解释方法,这个方法为抽象语法树中所有的节点所共享
  • 终结符表达式(TerminalExpression): 实现与文法中的终结符相关的解释操作
  • 非终结符表达式(NonTermialExpression): 为文法中的非终结符实现解释操作
  • Client:通过Client输入Context和TerminalExpression信息

实现

通过解释器模式来实现整数四则运算,如计算a+b-c的值,具体要求

  1. 先输入表达式的形式,比如a+b+c-d+e, 要求表达式的字母不能重复
  2. 再分别输入a ,b, c, d, e的值
  3. 最后求出结果
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Stack;

public class InterpreterTest {

    public static void main(String[] args) throws IOException {
        // 例如:expStr = a+b-c
        String expStr = getExpStr();
        // 例如:inputMap = {a=10, b=30, c=20}
        HashMap<String, Integer> inputMap = getInputMap(expStr);
        // 进行计算器表达式的构造
        Calculator calculator = new Calculator(expStr);
        // 将inputMap传入计算器表达式,进行计算
        System.out.println("运算结果:" + expStr + " = " + calculator.run(inputMap));
    }

    // 获取用户输入的字符串表达式
    public static String getExpStr() throws IOException {
        System.out.print("请输入表达式:");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    // 获得用户输入的字符串表达式,各个变量及其值HashMap
    public static HashMap<String, Integer> getInputMap(String expStr) throws IOException {
        HashMap<String, Integer> hashMap = new HashMap<>();

        for (char ch : expStr.toCharArray()) {
            if (ch != '+' && ch != '-' && ch != ' ') {
                // hashMap右的变量则不处理
                if (!hashMap.containsKey(String.valueOf(ch))) {
                    System.out.print("请输入" + String.valueOf(ch) + "的值:");
                    String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                    hashMap.put(String.valueOf(ch), Integer.valueOf(in));
                }
            }
        }

        return hashMap;
    }
}


// 抽象表达式-变量表达式和运算符表达式的父类
abstract class Expression {

    // 由子类进行具体的实现
    // 如果是变量表达式子类,则从HashMap通过key获取值
    // 如果是运算符表达式子类,则进行运算符操作。如果运算符左右两边还是运算符表达式,则递归调用
    public abstract int interpreter(HashMap<String, Integer> inputMap);
}


// 终结符表达式-变量表达式
class VarExpression extends Expression {

    // 变量的key
    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    // 从HashMap通过key获取值
    @Override
    public int interpreter(HashMap<String, Integer> inputMap) {
        return inputMap.get(this.key);
    }
}


// 非终结符表达式-运算符表达式
class SymbolExpression extends Expression {

    // 左右表达式,可以是值表达式,也可以是运算符表达式
    protected Expression left;
    protected Expression right;

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

    // 具体的实现由子类去实现。这里只提供默认实现
    @Override
    public int interpreter(HashMap<String, Integer> inputMap) {
        return 0;
    }
}


// 非终结符表达式具体实现-加法表达式
class AddExpression extends SymbolExpression {

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    // 进行加法运算符操作。如果运算符左右两边是值表达式,则从HashMap获取值相加
    // 如果是运算符表达式,则递归调用
    public int interpreter(HashMap<String, Integer> inputMap) {

        return super.left.interpreter(inputMap) + super.right.interpreter(inputMap);
    }
}

// 非终结符表达式具体实现-减法表达式
class SubExpression extends SymbolExpression {

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    public int interpreter(HashMap<String, Integer> inputMap) {
        return super.left.interpreter(inputMap) - super.right.interpreter(inputMap);
    }
}

// 环境角色-计算器
class Calculator {

    // 计算器要进行计算的表达式
    private Expression expression;

    // 解析传入的字符串表达式,构造计算器要进行计算的表达式
    // 例如:expStr = a+b-c
    public Calculator(String expStr) {
        // 用栈来存取一个临时的计算器表达式
        Stack<Expression> stack = new Stack<>();
        // 将字符串表达式拆分成字符数组
        char[] charArray = expStr.toCharArray();

        // 用于存放临时的左右表达式
        Expression left = null;
        Expression right = null;
        // 遍历字符数组,根据不同的情况做不同的处理
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
                case '+':
                    // 从栈中获取临时的计算器表达式,赋值给临时的左表达式
                    left = stack.pop();
                    // 运算符后面的空字符则直接跳过
                    while (String.valueOf(charArray[++i]) == " ") {

                    }
                    // 将运算符后面的变量,构造成值表达式,然后赋值给临时的右表达式
                    right = new VarExpression(String.valueOf(charArray[i]));
                    // 根据左右表达式构造出加法表达式,作为临时的计算器表达式传入栈中
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                    left = stack.pop();
                    while (String.valueOf(charArray[++i]) == " ") {

                    }
                    right = new VarExpression(String.valueOf(charArray[i]));
                    stack.push(new SubExpression(left, right));
                    break;
                case ' ':
                    break;
                default:
                    // 剩余的就是变量,构造成值表达式,作为临时的计算器表达式传入栈中
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    break;
            }
        }
        // 当遍历完整个charArray数组后,从栈中获取计算器表达式
        this.expression = stack.pop();
    }

    public int run(HashMap<String, Integer> inputMap) {

        // 将用户输入的表达式的值HashMap,传入给计算器表达式进行计算
        return this.expression.interpreter(inputMap);
    }
}

运行程序,结果如下:

请输入表达式:a + b - c
请输入a的值:10
请输入b的值:30
请输入c的值:20
运算结果:a + b - c = 20

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 雅思 Band 7+ 预备课程
  • CSS背景(background)
  • Linux上快速安装zookeeper
  • MySQL主从复制架构实现
  • stack使用+模拟实现
  • 软件测试中的集成测试到底是什么?集成的方法又有哪些?
  • centos安装NIS
  • pd.Series().rank()的个人理解
  • S32K1 Family Introduction
  • 美酒众耀 夏友云朋 | 瑞格尔侯爵佳酿亮相2022美夏中国区巡展
  • 国家高新技术企业认定条件和评分标准
  • MindManager21简体中文永久版思维导图
  • Java基础28(方法重载)
  • 计算机网络(自顶向下方法)-传输层
  • H5画布绘制渐变
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • AngularJS指令开发(1)——参数详解
  • go append函数以及写入
  • JDK 6和JDK 7中的substring()方法
  • October CMS - 快速入门 9 Images And Galleries
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Python_OOP
  • Yii源码解读-服务定位器(Service Locator)
  • 从零开始的无人驾驶 1
  • 搭建gitbook 和 访问权限认证
  • 讲清楚之javascript作用域
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • elasticsearch-head插件安装
  • 阿里云ACE认证之理解CDN技术
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • # 利刃出鞘_Tomcat 核心原理解析(八)-- Tomcat 集群
  • #NOIP 2014# day.2 T2 寻找道路
  • #数学建模# 线性规划问题的Matlab求解
  • $jQuery 重写Alert样式方法
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (PADS学习)第二章:原理图绘制 第一部分
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (简单) HDU 2612 Find a way,BFS。
  • (译)计算距离、方位和更多经纬度之间的点
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)3D模板阴影原理
  • (转)linux下的时间函数使用
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)大型网站架构演变和知识体系
  • .mp4格式的视频为何不能通过video标签在chrome浏览器中播放?
  • .NET C# 配置 Options
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET Project Open Day(2011.11.13)
  • .project文件
  • .py文件应该怎样打开?
  • .考试倒计时43天!来提分啦!
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?