跟我学Java设计模式第7天:行为型设计模式

2023-11-16

Java设计模式文章目录

跟我学Java设计模式第一天:设计模式概述和软件设计原则

跟我学Java设计模式第二天:简单工厂模式、工厂方法模式、抽象工厂模式

跟我学Java设计模式第三天:代理模式、适配器、装饰者等其中模式结构

跟我学Java设计模式第4天:结构型模式大全

跟我学Java设计模式第5天:行为型设计模式汇总

跟我学Java设计模式第6天:行为型设计模式汇总源码



6,行为型模式

6.11 解释器模式

6.11.1 概述

请添加图片描述

如上图,设计一个软件用来进行加减计算。我们第一想法就是使用工具类,提供对应的加法和减法的工具方法。

//用于两个整数相加
public static int add(int a,int b){
    return a + b;
}

//用于两个整数相加
public static int add(int a,int b,int c){
    return a + b + c;
}

//用于n个整数相加
public static int add(Integer ... arr) {
    int sum = 0;
    for (Integer i : arr) {
        sum += i;
    }
    return sum;
}

上面的形式比较单一、有限,如果形式变化非常多,这就不符合要求,因为加法和减法运算,两个运算符与数值可以有无限种组合方式。比如 1+2+3+4+5、1+2+3-4等等。

显然,现在需要一种翻译识别机器,能够解析由数字以及 + - 符号构成的合法的运算序列。如果把运算符和数字都看作节点的话,能够逐个节点的进行读取解析运算,这就是解释器模式的思维。

定义:

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

在解释器模式中,我们需要将待解决的问题,提取出规则,抽象为一种“语言”。比如加减法运算,规则为:由数值和±符号组成的合法序列,“1+3-2” 就是这种语言的句子。

解释器就是要解析出来语句的含义。但是如何描述规则呢?

文法(语法)规则:

文法是用于描述语言的语法结构的形式规则。

expression ::= value | plus | minus
plus ::= expression ‘+’ expression   
minus ::= expression ‘-’ expression  
value ::= integer

注意: 这里的符号“::=”表示“定义为”的意思,竖线 | 表示或,左右的其中一个,引号内为字符本身,引号外为语法。

上面规则描述为 :

表达式可以是一个值,也可以是plus或者minus运算,而plus和minus又是由表达式结合运算符构成,值的类型为整型数。

抽象语法树:

在计算机科学中,抽象语法树(AbstractSyntaxTree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

用树形来表示符合文法规则的句子。

在这里插入图片描述

6.11.2 结构

解释器模式包含以下主要角色。

  • 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。

  • 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。

  • 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。

  • 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。

  • 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

6.11.3 案例实现

【例】设计实现加减法的软件

代码如下:

//抽象角色AbstractExpression
public abstract class AbstractExpression {
    public abstract int interpret(Context context);
}

//终结符表达式角色
public class Value extends AbstractExpression {
    private int value;

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

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

    @Override
    public String toString() {
        return new Integer(value).toString();
    }
}

//非终结符表达式角色  加法表达式
public class Plus extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public Plus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

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

    @Override
    public String toString() {
        return "(" + left.toString() + " + " + right.toString() + ")";
    }
}

///非终结符表达式角色 减法表达式
public class Minus extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public Minus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) - right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " - " + right.toString() + ")";
    }
}

//终结符表达式角色 变量表达式
public class Variable extends AbstractExpression {
    private String name;

    public Variable(String name) {
        this.name = name;
    }

    @Override
    public int interpret(Context ctx) {
        return ctx.getValue(this);
    }

    @Override
    public String toString() {
        return name;
    }
}

//环境类
public class Context {
    private Map<Variable, Integer> map = new HashMap<Variable, Integer>();

    public void assign(Variable var, Integer value) {
        map.put(var, value);
    }

    public int getValue(Variable var) {
        Integer value = map.get(var);
        return value;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        Context context = new Context();

        Variable a = new Variable("a");
        Variable b = new Variable("b");
        Variable c = new Variable("c");
        Variable d = new Variable("d");
        Variable e = new Variable("e");
        //Value v = new Value(1);

        context.assign(a, 1);
        context.assign(b, 2);
        context.assign(c, 3);
        context.assign(d, 4);
        context.assign(e, 5);

        AbstractExpression expression = new Minus(new Plus(new Plus(new Plus(a, b), c), d), e);

        System.out.println(expression + "= " + expression.interpret(context));
    }
}

6.11.4 优缺点

1,优点:

  • 易于改变和扩展文法。

    由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

  • 实现文法较为容易。

    在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂。

  • 增加新的解释表达式较为方便。

    如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合 “开闭原则”。

2,缺点:

  • 对于复杂文法难以维护。

    在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护。

  • 执行效率较低。

    由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

6.11.5 使用场景

  • 当语言的文法较为简单,且执行效率不是关键问题时。

  • 当问题重复出现,且可以用一种简单的语言来进行表达时。

  • 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

跟我学Java设计模式第7天:行为型设计模式 的相关文章

随机推荐

  • Windows下Jenkins的运行环境由Java8 升级为Java11

    开源 Devops 工具 Jenkins 在官方博客宣布 从 6 月 28 日发布的 Jenkins 2 357 和将于 9 月发布的 LTS 版本开始 Jenkins 需要 Java 11 才能使用 将放弃 Java 8 步骤 1 安装j
  • STM32CUBEMX配置教程(一)基础配置

    STM32CUBEMX配置教程 一 基础配置 基于STM32H743VI 使用STM32CUBEMX两年了 始终觉得这个工具非常的方便 但因为不是经常使用 导致有些要点总是会有些遗忘 因此写下这一系列教程以供记忆 顺便让我这个大萌新给广大小
  • c++智能指针之auto_ptr详解(有源码有实例)

    前言 内存泄漏大概是每一个c c 程序员最深恶痛绝的问题 因为大部分此类问题都是令广大c程序员很抓狂 掉头发的疑难杂症 而内存泄漏的根本原因就是指针的使用不当引起的 例如指针指向的内存没有释放 导致产生了程序无法控制的内存块 而随着程序不断
  • Pycharm连接MySQL

    使用MySQL内置工具 命令 创建数据库 unicom 数据表 admin 表名 admin 列 id 整型 自增 主键 username 字符串 不为空 password 字符串 不为空 mobile 字符串 不为空 Python代码实现
  • VC++实现视频压缩编码标准 MPEG-4

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家提出意见 一起讨论 需要源码的请与我联系 参考书籍 lt
  • 测试人如何编写测试用例?一文从3个方面带你写一个合格的测试用例

    前言 作为一个测试新人 刚开始接触测试 对于怎么写测试用例很头疼 无法接触需求 只能根据站在用户的角度去做测试 但是这样情况会导致不能全方位的测试APP 这种情况就需要一份测试用例了 但是不会写 求指教 还有就是测试出来的bug该如何追踪
  • 访问数据库

    一 JDBC简介 JDBC时Java DataBase Connectivity的缩写 它是连接Java程序和数据库服务器的纽带 JDBC的实现封装了与各种数据库服务器通信的细节 Java程序通过JDBC API来访问数据库 有以下优点 1
  • 【leetcode刷题】最长回文子串

    题目描述 给你一个字符串 s 找到 s 中最长的回文子串 示例1 输入 s babad 输出 bab 解释 aba 同样是符合题意的答案 示例2 输入 s cbbd 输出 bb 方法一 暴力枚举 param string s return
  • 单片机概述习题以及答案

    一 填空 除了单片机这一名称之外 单片机还可称为 或 答 微控制器 嵌入式控制器 2 单片机与普通微型计算机的不同之处在于其将 和 三部分 通过内部 连接在一起 集成于一块芯片上 答 CPU 存储器 I O 口 总线 AT89S52 单片机
  • 线性代数期末抱佛脚

    1 Row operations steps for finding solution if possible in linear systems many linear equations 求解的方法有两种 第一种 如 若要求该矩阵的解
  • LSTM对比Bi-LSTM的电力负荷时间序列预测(Matlab)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 0 概述 1 电力负荷预测 2 滑动窗输入结构的构建 3 LSTM 4 Bi LSTM 5 运行结果 6 Matla
  • jQuery MiniUI 开发教程 树形控件 树形:懒加载树(五)

    b 懒加载树 b img http www miniui com docs api images lazytree gif img 参考示例 url http www miniui com demo tree lazytree html 懒
  • C++:读写INI文件

    C 读写INI文件 INI文件是一种常见的配置文件格式 用于存储应用程序的配置信息 在C 中 我们可以使用一些库来读取和写入INI文件 在本文中 我将向您展示如何使用C 读取和写入INI文件 读取INI文件 对于INI文件的读取 我们可以使
  • Spring Data JPA 多数据源的使用

    p 项目中使用多个数据源在以往工作中比较常见 微服务架构中不建议一个项目使用多个数据源 在微服务架构下 一个微服务拥有自己独立的一个数据库 如果此微服务要使用其他数据库的数据 需要调用对应库的微服务接口来调用 而不是在一个项目中连接使用多个
  • U盘安装redhat 7.4的最终解决方案

    U盘安装redhat 7 4的最终解决方案 终于将redhat 7 4装上x3650 M5服务器了 过程无比艰辛 因为与CentOS7有一定区别 与redhat6 8完全不同 遇到的问题有 A 刻录镜像的时候只能刻录一个4MB EFI文件夹
  • 详解TCP为什么不能是两次握手

    三次握手的过程 注意不要遗漏全双工下两缓存 读 写缓存 的分配和变量的分配 CLOSED 表示初始状态 LISTEN 该状态表示服务器端的某个SOCKET处于监听状态 可以接受连接 SYN SENT 这个状态与SYN RCVD遥相呼应 当客
  • 【golang】for range中取地址操作的陷阱

    Tips for range创建了每个元素的副本 而不是直接返回每个元素的引用 例子1 package main import fmt func main slice int 0 1 2 3 myMap make map int int f
  • ZooKeeper之Java客户端API使用—创建节点。

    客户端可以通过ZooKeeper的API来创建一个数据节点 有如下两个接口 String create final String path byte data List
  • LeetCode-1604. 警告一小时内使用相同员工卡大于等于三次的人【哈希表,排序,数组】

    LeetCode 1604 警告一小时内使用相同员工卡大于等于三次的人 哈希表 排序 数组 题目描述 解题思路一 时间转换成分钟数 直接解决跨天问题 用哈希表记录每个员工的名字以及对应的时间 然后遍历哈希表 对于每个员工 我们将该员工的所有
  • 跟我学Java设计模式第7天:行为型设计模式

    Java设计模式文章目录 跟我学Java设计模式第一天 设计模式概述和软件设计原则 跟我学Java设计模式第二天 简单工厂模式 工厂方法模式 抽象工厂模式 跟我学Java设计模式第三天 代理模式 适配器 装饰者等其中模式结构 跟我学Java